Extend the fix for PR9614 to handle inline asm in the outer decl and
the inner decl being a builtin. This is needed to support the glibc headers
in fedora 16 (2.14).

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@146867 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 0e8468f..16d01ef 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -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<FunctionIsDirectlyRecursive> {
     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<FunctionIsDirectlyRecursive> 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<AsmLabelAttr>();
-      if (!Attr)
+      AsmLabelAttr *Attr = FD->getAttr<AsmLabelAttr>();
+      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<AsmLabelAttr>();
+    if (!Attr)
+      return false;
+    Name = Attr->getLabel();
+  } else {
+    Name = FD->getName();
+  }
 
-  FunctionIsDirectlyRecursive Walker(F);
-  Walker.TraverseFunctionDecl(const_cast<FunctionDecl*>(F));
+  FunctionIsDirectlyRecursive Walker(Name, Context.BuiltinInfo);
+  Walker.TraverseFunctionDecl(const_cast<FunctionDecl*>(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) {
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 4c31737..0517521 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -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;