[PATCH] CodeGen: Emit some functions as weak_odr under -fms-extensions

David Majnemer david.majnemer at gmail.com
Thu Mar 27 16:06:32 PDT 2014


Hi rnk, rsmith,

MSVC always emits inline functions marked with the extern storage class
specifier.  The result is something similar to the opposite of
__attribute__((gnu_inline)).

This extension is also available in C.

This fixes PR19264.

http://llvm-reviews.chandlerc.com/D3207

Files:
  include/clang/AST/Decl.h
  lib/AST/ASTContext.cpp
  lib/AST/Decl.cpp
  lib/CodeGen/CodeGenModule.cpp
  test/CodeGen/inline.c

Index: include/clang/AST/Decl.h
===================================================================
--- include/clang/AST/Decl.h
+++ include/clang/AST/Decl.h
@@ -1930,6 +1930,8 @@
 
   bool isInlineDefinitionExternallyVisible() const;
 
+  bool isMSExternInline() const;
+
   bool doesDeclarationForceExternallyVisibleDefinition() const;
 
   /// isOverloadedOperator - Whether this function declaration
Index: lib/AST/ASTContext.cpp
===================================================================
--- lib/AST/ASTContext.cpp
+++ lib/AST/ASTContext.cpp
@@ -7830,8 +7830,9 @@
     // static, static inline, always_inline, and extern inline functions can
     // always be deferred.  Normal inline functions can be deferred in C99/C++.
     // Implicit template instantiations can also be deferred in C++.
-    if (Linkage == GVA_Internal  || Linkage == GVA_C99Inline ||
-        Linkage == GVA_CXXInline || Linkage == GVA_TemplateInstantiation)
+    if (Linkage == GVA_Internal || Linkage == GVA_C99Inline ||
+        (Linkage == GVA_CXXInline && !FD->isMSExternInline()) ||
+        Linkage == GVA_TemplateInstantiation)
       return false;
     return true;
   }
Index: lib/AST/Decl.cpp
===================================================================
--- lib/AST/Decl.cpp
+++ lib/AST/Decl.cpp
@@ -2582,6 +2582,26 @@
   return false;
 }
 
+// \brief The combination of the extern and inline keywords under MSVC forces
+// the function to be required.
+bool FunctionDecl::isMSExternInline() const {
+  const ASTContext &Context = getASTContext();
+  if (!Context.getLangOpts().MicrosoftExt)
+    return false;
+
+  bool IsExternSpecified = false;
+  bool IsInlineSpecified = false;
+  const FunctionDecl *FD = getMostRecentDecl();
+  do {
+    IsInlineSpecified |= FD->isInlineSpecified();
+    IsExternSpecified |= FD->getStorageClass() == SC_Extern;
+    if (IsInlineSpecified && IsExternSpecified)
+      break;
+  } while ((FD = FD->getPreviousDecl()));
+
+  return IsInlineSpecified && IsExternSpecified;
+}
+
 /// \brief For a function declaration in C or C++, determine whether this
 /// declaration causes the definition to be externally visible.
 ///
Index: lib/CodeGen/CodeGenModule.cpp
===================================================================
--- lib/CodeGen/CodeGenModule.cpp
+++ lib/CodeGen/CodeGenModule.cpp
@@ -551,11 +551,20 @@
   // don't need to codegen it.  b) if the function persists, it needs to be
   // merged with other definitions. c) C++ has the ODR, so we know the
   // definition is dependable.
-  if (Linkage == GVA_CXXInline || Linkage == GVA_TemplateInstantiation)
-    return !Context.getLangOpts().AppleKext 
-             ? llvm::Function::LinkOnceODRLinkage 
-             : llvm::Function::InternalLinkage;
-  
+  if (Linkage == GVA_CXXInline || Linkage == GVA_TemplateInstantiation) {
+    if (Context.getLangOpts().AppleKext)
+      return llvm::Function::InternalLinkage;
+
+    // Functions specified with extern and inline in -fmicrosoft-extensions mode
+    // forcibly get emitted.  While the body of the function cannot be later
+    // replaced, the function definition cannot be discarded.
+    if (const auto *FD = dyn_cast<FunctionDecl>(D))
+      if (FD->isMSExternInline())
+        return llvm::Function::WeakODRLinkage;
+
+    return llvm::Function::LinkOnceODRLinkage;
+  }
+
   // An explicit instantiation of a template has weak linkage, since
   // explicit instantiations can occur in multiple translation units
   // and must all be equivalent. However, we are not allowed to
Index: test/CodeGen/inline.c
===================================================================
--- test/CodeGen/inline.c
+++ test/CodeGen/inline.c
@@ -53,12 +53,13 @@
 
 // RUN: echo "MS C Mode tests:"
 // RUN: %clang_cc1 %s -triple i386-unknown-unknown -O1 -disable-llvm-optzns -emit-llvm -o - -std=c99 -fms-compatibility | FileCheck %s --check-prefix=CHECK4
+// CHECK4-LABEL: define weak_odr i32 @ei()
 // CHECK4-LABEL: define i32 @bar()
+// CHECK4-NOT: unreferenced1
+// CHECK4-LABEL: define weak_odr void @unreferenced2()
 // CHECK4-LABEL: define void @gnu_inline()
 // CHECK4-LABEL: define available_externally void @gnu_ei_inline()
 // CHECK4-LABEL: define linkonce_odr i32 @foo()
-// CHECK4-NOT: unreferenced
-// CHECK4-LABEL: define linkonce_odr i32 @ei()
 
 extern __inline int ei() { return 123; }
-------------- next part --------------
A non-text attachment was scrubbed...
Name: D3207.1.patch
Type: text/x-patch
Size: 4366 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20140327/5d2e2245/attachment.bin>


More information about the cfe-commits mailing list