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 @@ -468,7 +468,6 @@ bool hasSameVisibilityContextAndLinkage(T *Found, T *From); bool IsStructuralMatch(Decl *From, Decl *To, bool Complain = true); - bool IsStructuralMatch(EnumConstantDecl *FromEC, EnumConstantDecl *ToEC); ExpectedDecl VisitDecl(Decl *D); ExpectedDecl VisitImportDecl(ImportDecl *D); ExpectedDecl VisitEmptyDecl(EmptyDecl *D); @@ -2182,16 +2181,6 @@ return Ctx.IsEquivalent(From, To); } -bool ASTNodeImporter::IsStructuralMatch(EnumConstantDecl *FromEC, - EnumConstantDecl *ToEC) { - const llvm::APSInt &FromVal = FromEC->getInitVal(); - const llvm::APSInt &ToVal = ToEC->getInitVal(); - - return FromVal.isSigned() == ToVal.isSigned() && - FromVal.getBitWidth() == ToVal.getBitWidth() && - FromVal == ToVal; -} - ExpectedDecl ASTNodeImporter::VisitDecl(Decl *D) { Importer.FromDiag(D->getLocation(), diag::err_unsupported_ast_node) << D->getDeclKindName(); 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 @@ -1591,6 +1591,26 @@ return true; } +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + EnumConstantDecl *D1, + EnumConstantDecl *D2) { + const llvm::APSInt &FromVal = D1->getInitVal(); + const llvm::APSInt &ToVal = D2->getInitVal(); + if (FromVal.isSigned() != ToVal.isSigned()) + return false; + if (FromVal.getBitWidth() != ToVal.getBitWidth()) + return false; + if (FromVal != ToVal) + return false; + + if (!IsStructurallyEquivalent(D1->getIdentifier(), D2->getIdentifier())) + return false; + + // Init expressions are the most expensive check, so do them last. + return IsStructurallyEquivalent(Context, D1->getInitExpr(), + D2->getInitExpr()); +} + /// Determine structural equivalence of two enums. static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, EnumDecl *D1, EnumDecl *D2) { 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 @@ -956,6 +956,48 @@ EXPECT_FALSE(testStructuralMatch(t)); } +struct StructuralEquivalenceEnumConstantTest : StructuralEquivalenceTest {}; + +TEST_F(StructuralEquivalenceEnumConstantTest, EnumConstantsWithSameValues) { + auto t = makeNamedDecls("enum foo { foo = 1 };", "enum foo { foo = 1 };", + Lang_C89); + EXPECT_TRUE(testStructuralMatch(t)); +} + +TEST_F(StructuralEquivalenceEnumConstantTest, + EnumConstantsWithDifferentValues) { + auto t = + makeNamedDecls("enum e { foo = 1 };", "enum e { foo = 2 };", Lang_C89); + EXPECT_FALSE(testStructuralMatch(t)); +} + +TEST_F(StructuralEquivalenceEnumConstantTest, + EnumConstantsWithDifferentExprsButSameValues) { + auto t = makeNamedDecls("enum e { foo = 1 + 1 };", "enum e { foo = 2 };", + Lang_CXX11); + EXPECT_FALSE(testStructuralMatch(t)); +} + +TEST_F(StructuralEquivalenceEnumConstantTest, + EnumConstantsWithDifferentSignedness) { + auto t = makeNamedDecls("enum e : unsigned { foo = 1 };", + "enum e : int { foo = 1 };", Lang_CXX11); + EXPECT_FALSE(testStructuralMatch(t)); +} + +TEST_F(StructuralEquivalenceEnumConstantTest, EnumConstantsWithDifferentWidth) { + auto t = makeNamedDecls("enum e : short { foo = 1 };", + "enum e : int { foo = 1 };", Lang_CXX11); + EXPECT_FALSE(testStructuralMatch(t)); +} + +TEST_F(StructuralEquivalenceEnumConstantTest, EnumConstantsWithDifferentName) { + auto t = + makeDecls("enum e { foo = 1 };", "enum e { bar = 1 };", + Lang_CXX11, enumConstantDecl()); + EXPECT_FALSE(testStructuralMatch(t)); +} + struct StructuralEquivalenceTemplateTest : StructuralEquivalenceTest {}; TEST_F(StructuralEquivalenceTemplateTest, ExactlySameTemplates) {