Fix PR3988: extern inline functions get strong symbol definitions in
C99 mode.  This is a regression from an earlier patch of mine.

This also simplifies the linkage enums a bit.


git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69069 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp
index 3f1d412..ef9404a 100644
--- a/lib/CodeGen/CodeGenModule.cpp
+++ b/lib/CodeGen/CodeGenModule.cpp
@@ -229,26 +229,32 @@
     return CodeGenModule::GVA_Internal;
 
   if (!FD->isInline())
-    return CodeGenModule::GVA_Normal;
+    return CodeGenModule::GVA_StrongExternal;
   
-  if (FD->getStorageClass() == FunctionDecl::Extern)
-    return CodeGenModule::GVA_ExternInline;
-
   // If the inline function explicitly has the GNU inline attribute on it, then
-  // force to GNUC semantics, regardless of language.
+  // force to GNUC semantics (which is strong external), regardless of language.
   if (FD->hasAttr<GNUCInlineAttr>())
-    return CodeGenModule::GVA_GNUCInline;
-  
+    return CodeGenModule::GVA_StrongExternal;
+
   // The definition of inline changes based on the language.  Note that we
   // have already handled "static inline" above, with the GVA_Internal case.
-  if (Features.CPlusPlus)
+  if (Features.CPlusPlus)  // inline and extern inline.
     return CodeGenModule::GVA_CXXInline;
   
+  if (FD->getStorageClass() == FunctionDecl::Extern) {
+    // extern inline in C99 is a strong definition. In C89, it is extern inline.
+    if (Features.C99)
+      return CodeGenModule::GVA_StrongExternal;
+    
+    // In C89 mode, an 'extern inline' works like a C99 inline function.
+    return CodeGenModule::GVA_C99Inline;
+  }
+  
   if (Features.C99)
     return CodeGenModule::GVA_C99Inline;
   
   // Otherwise, this is the GNU inline extension in K&R and GNU C89 mode.
-  return CodeGenModule::GVA_GNUCInline;
+  return CodeGenModule::GVA_StrongExternal;
 }
 
 /// SetFunctionDefinitionAttributes - Set attributes for a global.
@@ -266,10 +272,9 @@
     GV->setLinkage(llvm::Function::DLLExportLinkage);
   } else if (D->hasAttr<WeakAttr>() || D->hasAttr<WeakImportAttr>()) {
     GV->setLinkage(llvm::Function::WeakAnyLinkage);
-  } else if (Linkage == GVA_ExternInline) {
-    // "extern inline" always gets available_externally linkage, which is the
-    // strongest linkage type we can give an inline function: we don't have to
-    // codegen the definition at all, yet we know that it is "ODR".
+  } else if (Linkage == GVA_C99Inline) {
+    // In C99 mode, 'inline' functions are guaranteed to have a strong
+    // definition somewhere else, so we can use available_externally linkage.
     GV->setLinkage(llvm::Function::AvailableExternallyLinkage);
   } else if (Linkage == GVA_CXXInline) {
     // In C++, the compiler has to emit a definition in every translation unit
@@ -279,16 +284,9 @@
     // merged with other definitions. c) C++ has the ODR, so we know the
     // definition is dependable.
     GV->setLinkage(llvm::Function::LinkOnceODRLinkage);
-  } else if (Linkage == GVA_C99Inline) {
-    // In C99 mode, 'inline' functions are guaranteed to have a strong
-    // definition somewhere else, so we can use available_externally linkage.
-    GV->setLinkage(llvm::Function::AvailableExternallyLinkage);
-  } else if (Linkage == GVA_GNUCInline) {
-    // In C89 mode, an 'inline' function may only occur in one translation
-    // unit in the program, but may be extern'd in others.  Give it strong
-    // external linkage.
-    GV->setLinkage(llvm::Function::ExternalLinkage);
   } else {
+    assert(Linkage == GVA_StrongExternal);
+    // Otherwise, we have strong external linkage.
     GV->setLinkage(llvm::Function::ExternalLinkage);
   }
 
@@ -481,8 +479,8 @@
     
     // static, static inline, always_inline, and extern inline functions can
     // always be deferred.  Normal inline functions can be deferred in C99/C++.
-    if (Linkage == GVA_Internal || Linkage == GVA_ExternInline ||
-        Linkage == GVA_C99Inline || Linkage == GVA_CXXInline)
+    if (Linkage == GVA_Internal || Linkage == GVA_C99Inline ||
+        Linkage == GVA_CXXInline)
       return true;
     return false;
   }
diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h
index 06118ac..ff6c405 100644
--- a/lib/CodeGen/CodeGenModule.h
+++ b/lib/CodeGen/CodeGenModule.h
@@ -315,10 +315,9 @@
   enum GVALinkage {
     GVA_Internal,
     GVA_ExternInline,
-    GVA_GNUCInline,
     GVA_C99Inline,
     GVA_CXXInline,
-    GVA_Normal
+    GVA_StrongExternal
   };
   
 private: