Index: test/CodeGen/pr9614.c =================================================================== --- test/CodeGen/pr9614.c (revision 146866) +++ test/CodeGen/pr9614.c (revision 146867) @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -emit-llvm %s -O1 -o - | FileCheck %s +// RUN: %clang_cc1 -emit-llvm %s -o - | FileCheck %s extern void foo_alias (void) __asm ("foo"); inline void foo (void) { @@ -8,15 +8,22 @@ inline __attribute__ ((__always_inline__)) void bar (void) { return bar_alias (); } +extern char *strrchr_foo (const char *__s, int __c) __asm ("strrchr"); +extern inline __attribute__ ((__always_inline__)) __attribute__ ((__gnu_inline__)) char * strrchr_foo (const char *__s, int __c) { + return __builtin_strrchr (__s, __c); +} void f(void) { foo(); bar(); + strrchr_foo("", '.'); } // CHECK: define void @f() // CHECK: call void @foo() // CHECK-NEXT: call void @bar() +// CHECK-NEXT: call i8* @strrchr( // CHECK-NEXT: ret void // CHECK: declare void @foo() // CHECK: declare void @bar() +// CHECK: declare i8* @strrchr(i8*, i32) Index: lib/CodeGen/CodeGenModule.h =================================================================== --- lib/CodeGen/CodeGenModule.h (revision 146866) +++ lib/CodeGen/CodeGenModule.h (revision 146867) @@ -323,7 +323,7 @@ void createOpenCLRuntime(); void createCUDARuntime(); - bool isTriviallyRecursiveViaAsm(const FunctionDecl *F); + bool isTriviallyRecursive(const FunctionDecl *F); bool shouldEmitFunction(const FunctionDecl *F); llvm::LLVMContext &VMContext; Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp (revision 146866) +++ lib/CodeGen/CodeGenModule.cpp (revision 146867) @@ -30,6 +30,7 @@ #include "clang/AST/Mangle.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/RecursiveASTVisitor.h" +#include "clang/Basic/Builtins.h" #include "clang/Basic/Diagnostic.h" #include "clang/Basic/SourceManager.h" #include "clang/Basic/TargetInfo.h" @@ -863,20 +864,27 @@ struct FunctionIsDirectlyRecursive : public RecursiveASTVisitor { const StringRef Name; + const Builtin::Context &BI; bool Result; - FunctionIsDirectlyRecursive(const FunctionDecl *F) : - Name(F->getName()), Result(false) { + FunctionIsDirectlyRecursive(StringRef N, const Builtin::Context &C) : + Name(N), BI(C), Result(false) { } typedef RecursiveASTVisitor Base; bool TraverseCallExpr(CallExpr *E) { - const Decl *D = E->getCalleeDecl(); - if (!D) + const FunctionDecl *FD = E->getDirectCallee(); + if (!FD) return true; - AsmLabelAttr *Attr = D->getAttr(); - if (!Attr) + AsmLabelAttr *Attr = FD->getAttr(); + if (Attr && Name == Attr->getLabel()) { + Result = true; + return false; + } + unsigned BuiltinID = FD->getBuiltinID(); + if (!BuiltinID) return true; - if (Name == Attr->getLabel()) { + const char *BuiltinName = BI.GetName(BuiltinID) + strlen("__builtin_"); + if (Name == BuiltinName) { Result = true; return false; } @@ -885,15 +893,24 @@ }; } -// isTriviallyRecursiveViaAsm - Check if this function calls another -// decl that, because of the asm attribute, ends up pointing to itself. +// isTriviallyRecursive - Check if this function calls another +// decl that, because of the asm attribute or the other decl being a builtin, +// ends up pointing to itself. bool -CodeGenModule::isTriviallyRecursiveViaAsm(const FunctionDecl *F) { - if (getCXXABI().getMangleContext().shouldMangleDeclName(F)) - return false; +CodeGenModule::isTriviallyRecursive(const FunctionDecl *FD) { + StringRef Name; + if (getCXXABI().getMangleContext().shouldMangleDeclName(FD)) { + // asm labels are a special king of mangling we have to support. + AsmLabelAttr *Attr = FD->getAttr(); + if (!Attr) + return false; + Name = Attr->getLabel(); + } else { + Name = FD->getName(); + } - FunctionIsDirectlyRecursive Walker(F); - Walker.TraverseFunctionDecl(const_cast(F)); + FunctionIsDirectlyRecursive Walker(Name, Context.BuiltinInfo); + Walker.TraverseFunctionDecl(const_cast(FD)); return Walker.Result; } @@ -909,7 +926,7 @@ // but a function that calls itself is clearly not equivalent to the real // implementation. // This happens in glibc's btowc and in some configure checks. - return !isTriviallyRecursiveViaAsm(F); + return !isTriviallyRecursive(F); } void CodeGenModule::EmitGlobalDefinition(GlobalDecl GD) {