aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/CodeGen/CGExpr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/CodeGen/CGExpr.cpp')
-rw-r--r--clang/lib/CodeGen/CGExpr.cpp14
1 files changed, 12 insertions, 2 deletions
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index bb5d18b74894..2a9b108c31bc 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -4895,6 +4895,16 @@ RValue CodeGenFunction::EmitSimpleCallExpr(const CallExpr *E,
return EmitCall(E->getCallee()->getType(), Callee, E, ReturnValue);
}
+// Detect the unusual situation where an inline version is shadowed by a
+// non-inline version. In that case we should pick the external one
+// everywhere. That's GCC behavior too.
+static bool OnlyHasInlineBuiltinDeclaration(const FunctionDecl *FD) {
+ for (const FunctionDecl *PD = FD; PD; PD = PD->getPreviousDecl())
+ if (!PD->isInlineBuiltinDeclaration())
+ return false;
+ return true;
+}
+
static CGCallee EmitDirectCallee(CodeGenFunction &CGF, GlobalDecl GD) {
const FunctionDecl *FD = cast<FunctionDecl>(GD.getDecl());
@@ -4902,8 +4912,8 @@ static CGCallee EmitDirectCallee(CodeGenFunction &CGF, GlobalDecl GD) {
std::string FDInlineName = (FD->getName() + ".inline").str();
// When directing calling an inline builtin, call it through it's mangled
// name to make it clear it's not the actual builtin.
- if (FD->isInlineBuiltinDeclaration() &&
- CGF.CurFn->getName() != FDInlineName) {
+ if (CGF.CurFn->getName() != FDInlineName &&
+ OnlyHasInlineBuiltinDeclaration(FD)) {
llvm::Constant *CalleePtr = EmitFunctionDeclPointer(CGF.CGM, GD);
llvm::Function *Fn = llvm::cast<llvm::Function>(CalleePtr);
llvm::Module *M = Fn->getParent();