From: Gabor Marton Date: Thu, 24 Jan 2019 14:47:44 +0000 (+0000) Subject: [ASTImporter] Fix inequality of functions with different attributes X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=899258dc2ec96c37720d783b826c0119d26981b0;p=clang [ASTImporter] Fix inequality of functions with different attributes Summary: FunctionType::ExtInfo holds such properties of a function which are needed mostly for code gen. We should not compare these bits when checking for structural equivalency. Checking ExtInfo caused false ODR errors during CTU analysis (of tmux). Reviewers: a_sidorin, a.sidorin, shafik Subscribers: rnkovacs, dkrupp, Szelethus, cfe-commits Differential Revision: https://reviews.llvm.org/D53699 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@352050 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/AST/ASTStructuralEquivalence.cpp b/lib/AST/ASTStructuralEquivalence.cpp index 2f00d5adb1..7b62eb8862 100644 --- a/lib/AST/ASTStructuralEquivalence.cpp +++ b/lib/AST/ASTStructuralEquivalence.cpp @@ -296,6 +296,32 @@ static bool IsArrayStructurallyEquivalent(StructuralEquivalenceContext &Context, 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 @@ static bool IsStructurallyEquivalent(StructuralEquivalenceContext &Context, if (!IsStructurallyEquivalent(Context, Function1->getReturnType(), Function2->getReturnType())) return false; - if (Function1->getExtInfo() != Function2->getExtInfo()) + if (!IsStructurallyEquivalent(Context, Function1->getExtInfo(), + Function2->getExtInfo())) return false; break; } diff --git a/unittests/AST/StructuralEquivalenceTest.cpp b/unittests/AST/StructuralEquivalenceTest.cpp index cd1f01d4bf..c895f7a021 100644 --- a/unittests/AST/StructuralEquivalenceTest.cpp +++ b/unittests/AST/StructuralEquivalenceTest.cpp @@ -370,6 +370,31 @@ TEST_F(StructuralEquivalenceFunctionTest, NameInParenWithConst) { 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 { };