Index: lib/AST/ASTStructuralEquivalence.cpp =================================================================== --- lib/AST/ASTStructuralEquivalence.cpp +++ lib/AST/ASTStructuralEquivalence.cpp @@ -296,6 +296,32 @@ return true; } +/// Determine structural equivalence based on the ExtInfo of functions. This +/// is inspired by ASTContext::mergeFunctionTypes(), we compare calling +/// conventions bits but must not compare some other bits. +static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, + FunctionType::ExtInfo EI1, + FunctionType::ExtInfo EI2) { + // Compatible functions must have compatible calling conventions. + if (EI1.getCC() != EI2.getCC()) + return false; + + // Regparm is part of the calling convention. + if (EI1.getHasRegParm() != EI2.getHasRegParm()) + return false; + if (EI1.getRegParm() != EI2.getRegParm()) + return false; + + if (EI1.getProducesResult() != EI2.getProducesResult()) + return false; + if (EI1.getNoCallerSavedRegs() != EI2.getNoCallerSavedRegs()) + return false; + if (EI1.getNoCfCheck() != EI2.getNoCfCheck()) + return false; + + return true; +} + /// Determine structural equivalence of two types. static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, QualType T1, QualType T2) { @@ -539,7 +565,8 @@ if (!IsStructurallyEquivalent(Context, Function1->getReturnType(), Function2->getReturnType())) return false; - if (Function1->getExtInfo() != Function2->getExtInfo()) + if (!IsStructurallyEquivalent(Context, Function1->getExtInfo(), + Function2->getExtInfo())) return false; break; } Index: unittests/AST/StructuralEquivalenceTest.cpp =================================================================== --- unittests/AST/StructuralEquivalenceTest.cpp +++ unittests/AST/StructuralEquivalenceTest.cpp @@ -370,6 +370,31 @@ EXPECT_FALSE(testStructuralMatch(t)); } +TEST_F(StructuralEquivalenceFunctionTest, FunctionsWithDifferentNoreturnAttr) { + auto t = makeNamedDecls( + "__attribute__((noreturn)) void foo();", + " void foo();", + Lang_C); + EXPECT_TRUE(testStructuralMatch(t)); +} + +TEST_F(StructuralEquivalenceFunctionTest, + FunctionsWithDifferentCallingConventions) { + auto t = makeNamedDecls( + "__attribute__((fastcall)) void foo();", + "__attribute__((ms_abi)) void foo();", + Lang_C); + EXPECT_FALSE(testStructuralMatch(t)); +} + +TEST_F(StructuralEquivalenceFunctionTest, FunctionsWithDifferentSavedRegsAttr) { + auto t = makeNamedDecls( + "__attribute__((no_caller_saved_registers)) void foo();", + " void foo();", + Lang_C); + EXPECT_FALSE(testStructuralMatch(t)); +} + struct StructuralEquivalenceCXXMethodTest : StructuralEquivalenceTest { };