r205485 - CodeGen: Emit some functions as weak_odr under -fms-compatibility

David Majnemer david.majnemer at gmail.com
Wed Apr 2 16:17:29 PDT 2014


Author: majnemer
Date: Wed Apr  2 18:17:29 2014
New Revision: 205485

URL: http://llvm.org/viewvc/llvm-project?rev=205485&view=rev
Log:
CodeGen: Emit some functions as weak_odr under -fms-compatibility

Summary:
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.

Reviewers: rnk, rsmith

CC: cfe-commits

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

Modified:
    cfe/trunk/include/clang/AST/ASTContext.h
    cfe/trunk/include/clang/AST/Decl.h
    cfe/trunk/include/clang/Basic/Linkage.h
    cfe/trunk/lib/AST/ASTContext.cpp
    cfe/trunk/lib/AST/Decl.cpp
    cfe/trunk/lib/CodeGen/CodeGenModule.cpp
    cfe/trunk/test/CodeGen/inline.c
    cfe/trunk/test/CodeGenCXX/inline-functions.cpp

Modified: cfe/trunk/include/clang/AST/ASTContext.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/ASTContext.h?rev=205485&r1=205484&r2=205485&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/ASTContext.h (original)
+++ cfe/trunk/include/clang/AST/ASTContext.h Wed Apr  2 18:17:29 2014
@@ -2156,7 +2156,7 @@ public:
   /// when it is called.
   void AddDeallocation(void (*Callback)(void*), void *Data);
 
-  GVALinkage GetGVALinkageForFunction(const FunctionDecl *FD);
+  GVALinkage GetGVALinkageForFunction(const FunctionDecl *FD) const;
   GVALinkage GetGVALinkageForVariable(const VarDecl *VD);
 
   /// \brief Determines if the decl can be CodeGen'ed or deserialized from PCH

Modified: cfe/trunk/include/clang/AST/Decl.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Decl.h?rev=205485&r1=205484&r2=205485&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Decl.h (original)
+++ cfe/trunk/include/clang/AST/Decl.h Wed Apr  2 18:17:29 2014
@@ -1930,6 +1930,8 @@ public:
 
   bool isInlineDefinitionExternallyVisible() const;
 
+  bool isMSExternInline() const;
+
   bool doesDeclarationForceExternallyVisibleDefinition() const;
 
   /// isOverloadedOperator - Whether this function declaration

Modified: cfe/trunk/include/clang/Basic/Linkage.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Basic/Linkage.h?rev=205485&r1=205484&r2=205485&view=diff
==============================================================================
--- cfe/trunk/include/clang/Basic/Linkage.h (original)
+++ cfe/trunk/include/clang/Basic/Linkage.h Wed Apr  2 18:17:29 2014
@@ -63,7 +63,7 @@ enum GVALinkage {
   GVA_CXXInline,
   GVA_StrongExternal,
   GVA_TemplateInstantiation,
-  GVA_ExplicitTemplateInstantiation
+  GVA_StrongODR
 };
 
 inline bool isExternallyVisible(Linkage L) {

Modified: cfe/trunk/lib/AST/ASTContext.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/ASTContext.cpp?rev=205485&r1=205484&r2=205485&view=diff
==============================================================================
--- cfe/trunk/lib/AST/ASTContext.cpp (original)
+++ cfe/trunk/lib/AST/ASTContext.cpp Wed Apr  2 18:17:29 2014
@@ -7732,7 +7732,7 @@ QualType ASTContext::GetBuiltinType(unsi
   return getFunctionType(ResType, ArgTypes, EPI);
 }
 
-GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) {
+GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) const {
   if (!FD->isExternallyVisible())
     return GVA_Internal;
 
@@ -7744,7 +7744,7 @@ GVALinkage ASTContext::GetGVALinkageForF
     break;
 
   case TSK_ExplicitInstantiationDefinition:
-    return GVA_ExplicitTemplateInstantiation;
+    return GVA_StrongODR;
 
   case TSK_ExplicitInstantiationDeclaration:
   case TSK_ImplicitInstantiation:
@@ -7776,6 +7776,12 @@ GVALinkage ASTContext::GetGVALinkageForF
                                        == TSK_ExplicitInstantiationDeclaration)
     return GVA_C99Inline;
 
+  // Functions specified with extern and inline in -fms-compatibility mode
+  // forcibly get emitted.  While the body of the function cannot be later
+  // replaced, the function definition cannot be discarded.
+  if (FD->getMostRecentDecl()->isMSExternInline())
+    return GVA_StrongODR;
+
   return GVA_CXXInline;
 }
 
@@ -7793,7 +7799,7 @@ GVALinkage ASTContext::GetGVALinkageForV
   // Fall through to treat this like any other instantiation.
 
   case TSK_ExplicitInstantiationDefinition:
-    return GVA_ExplicitTemplateInstantiation;
+    return GVA_StrongODR;
 
   case TSK_ImplicitInstantiation:
     return GVA_TemplateInstantiation;

Modified: cfe/trunk/lib/AST/Decl.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/AST/Decl.cpp?rev=205485&r1=205484&r2=205485&view=diff
==============================================================================
--- cfe/trunk/lib/AST/Decl.cpp (original)
+++ cfe/trunk/lib/AST/Decl.cpp Wed Apr  2 18:17:29 2014
@@ -2546,6 +2546,37 @@ unsigned FunctionDecl::getMinRequiredArg
   return NumRequiredArgs;
 }
 
+/// \brief The combination of the extern and inline keywords under MSVC forces
+/// the function to be required.
+///
+/// Note: This function assumes that we will only get called when isInlined()
+/// would return true for this FunctionDecl.
+bool FunctionDecl::isMSExternInline() const {
+  assert(isInlined() && "expected to get called on an inlined function!");
+
+  const ASTContext &Context = getASTContext();
+  if (!Context.getLangOpts().MSVCCompat)
+    return false;
+
+  for (const FunctionDecl *FD = this; FD; FD = FD->getPreviousDecl())
+    if (FD->getStorageClass() == SC_Extern)
+      return true;
+
+  return false;
+}
+
+static bool redeclForcesDefMSVC(const FunctionDecl *Redecl) {
+  if (Redecl->getStorageClass() != SC_Extern)
+    return false;
+
+  for (const FunctionDecl *FD = Redecl->getPreviousDecl(); FD;
+       FD = FD->getPreviousDecl())
+    if (FD->getStorageClass() == SC_Extern)
+      return false;
+
+  return true;
+}
+
 static bool RedeclForcesDefC99(const FunctionDecl *Redecl) {
   // Only consider file-scope declarations in this test.
   if (!Redecl->getLexicalDeclContext()->isTranslationUnit())
@@ -2565,7 +2596,7 @@ static bool RedeclForcesDefC99(const Fun
 /// \brief For a function declaration in C or C++, determine whether this
 /// declaration causes the definition to be externally visible.
 ///
-/// Specifically, this determines if adding the current declaration to the set
+/// For instance, this determines if adding the current declaration to the set
 /// of redeclarations of the given functions causes
 /// isInlineDefinitionExternallyVisible to change from false to true.
 bool FunctionDecl::doesDeclarationForceExternallyVisibleDefinition() const {
@@ -2574,6 +2605,13 @@ bool FunctionDecl::doesDeclarationForceE
 
   ASTContext &Context = getASTContext();
 
+  if (Context.getLangOpts().MSVCCompat) {
+    const FunctionDecl *Definition;
+    if (hasBody(Definition) && Definition->isInlined() &&
+        redeclForcesDefMSVC(this))
+      return true;
+  }
+
   if (Context.getLangOpts().GNUInline || hasAttr<GNUInlineAttr>()) {
     // With GNU inlining, a declaration with 'inline' but not 'extern', forces
     // an externally visible definition.

Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=205485&r1=205484&r2=205485&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
+++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Wed Apr  2 18:17:29 2014
@@ -589,7 +589,7 @@ CodeGenModule::getFunctionLinkage(Global
   // explicit instantiations can occur in multiple translation units
   // and must all be equivalent. However, we are not allowed to
   // throw away these explicit instantiations.
-  if (Linkage == GVA_ExplicitTemplateInstantiation)
+  if (Linkage == GVA_StrongODR)
     return !Context.getLangOpts().AppleKext
              ? llvm::Function::WeakODRLinkage
              : llvm::Function::ExternalLinkage;
@@ -1948,8 +1948,7 @@ CodeGenModule::GetLLVMLinkageVarDefiniti
       return llvm::GlobalVariable::WeakODRLinkage;
     else
       return llvm::GlobalVariable::WeakAnyLinkage;
-  } else if (Linkage == GVA_TemplateInstantiation ||
-             Linkage == GVA_ExplicitTemplateInstantiation)
+  } else if (Linkage == GVA_TemplateInstantiation || Linkage == GVA_StrongODR)
     return llvm::GlobalVariable::WeakODRLinkage;
   else if (!getLangOpts().CPlusPlus && 
            ((!CodeGenOpts.NoCommon && !D->hasAttr<NoCommonAttr>()) ||

Modified: cfe/trunk/test/CodeGen/inline.c
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/inline.c?rev=205485&r1=205484&r2=205485&view=diff
==============================================================================
--- cfe/trunk/test/CodeGen/inline.c (original)
+++ cfe/trunk/test/CodeGen/inline.c Wed Apr  2 18:17:29 2014
@@ -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; }
 

Modified: cfe/trunk/test/CodeGenCXX/inline-functions.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGenCXX/inline-functions.cpp?rev=205485&r1=205484&r2=205485&view=diff
==============================================================================
--- cfe/trunk/test/CodeGenCXX/inline-functions.cpp (original)
+++ cfe/trunk/test/CodeGenCXX/inline-functions.cpp Wed Apr  2 18:17:29 2014
@@ -1,4 +1,5 @@
-// RUN: %clang_cc1 %s -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 %s -std=c++11 -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s --check-prefix=CHECK --check-prefix=NORMAL
+// RUN: %clang_cc1 %s -std=c++11 -fms-compatibility -triple=x86_64-apple-darwin10 -emit-llvm -o - | FileCheck %s --check-prefix=CHECK --check-prefix=MSVCCOMPAT
 // CHECK: ; ModuleID 
 
 struct A {
@@ -67,3 +68,56 @@ namespace test2 {
   }
   // CHECK-LABEL: define linkonce_odr void @_ZN5test21fERKNS_1AE
 }
+
+// MSVCCOMPAT-LABEL: define weak_odr void @_Z17ExternAndInlineFnv
+// NORMAL-NOT: _Z17ExternAndInlineFnv
+extern inline void ExternAndInlineFn() {}
+
+// MSVCCOMPAT-LABEL: define weak_odr void @_Z18InlineThenExternFnv
+// NORMAL-NOT: _Z18InlineThenExternFnv
+inline void InlineThenExternFn() {}
+extern void InlineThenExternFn();
+
+// CHECK-LABEL: define void @_Z18ExternThenInlineFnv
+extern void ExternThenInlineFn() {}
+
+// MSVCCOMPAT-LABEL: define weak_odr void @_Z25ExternThenInlineThenDefFnv
+// NORMAL-NOT: _Z25ExternThenInlineThenDefFnv
+extern void ExternThenInlineThenDefFn();
+inline void ExternThenInlineThenDefFn();
+void ExternThenInlineThenDefFn() {}
+
+// MSVCCOMPAT-LABEL: define weak_odr void @_Z25InlineThenExternThenDefFnv
+// NORMAL-NOT: _Z25InlineThenExternThenDefFnv
+inline void InlineThenExternThenDefFn();
+extern void InlineThenExternThenDefFn();
+void InlineThenExternThenDefFn() {}
+
+// MSVCCOMPAT-LABEL: define weak_odr i32 @_Z20ExternAndConstexprFnv
+// NORMAL-NOT: _Z17ExternAndConstexprFnv
+extern constexpr int ExternAndConstexprFn() { return 0; }
+
+// CHECK-NOT: _Z11ConstexprFnv
+constexpr int ConstexprFn() { return 0; }
+
+template <typename T>
+extern inline void ExternInlineOnPrimaryTemplate(T);
+
+// CHECK-LABEL: define void @_Z29ExternInlineOnPrimaryTemplateIiEvT_
+template <>
+void ExternInlineOnPrimaryTemplate(int) {}
+
+template <typename T>
+extern inline void ExternInlineOnPrimaryTemplateAndSpecialization(T);
+
+// MSVCCOMPAT-LABEL: define weak_odr void @_Z46ExternInlineOnPrimaryTemplateAndSpecializationIiEvT_
+// NORMAL-NOT: _Z46ExternInlineOnPrimaryTemplateAndSpecializationIiEvT_
+template <>
+extern inline void ExternInlineOnPrimaryTemplateAndSpecialization(int) {}
+
+struct TypeWithInlineMethods {
+  // CHECK-NOT: _ZN21TypeWithInlineMethods9StaticFunEv
+  static void StaticFun() {}
+  // CHECK-NOT: _ZN21TypeWithInlineMethods12NonStaticFunEv
+  void NonStaticFun() { StaticFun(); }
+};





More information about the cfe-commits mailing list