]> granicus.if.org Git - clang/commitdiff
CodeGen: Emit some functions as weak_odr under -fms-compatibility
authorDavid Majnemer <david.majnemer@gmail.com>
Wed, 2 Apr 2014 23:17:29 +0000 (23:17 +0000)
committerDavid Majnemer <david.majnemer@gmail.com>
Wed, 2 Apr 2014 23:17:29 +0000 (23:17 +0000)
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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@205485 91177308-0d34-0410-b5e6-96231b3b80d8

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

index 82a022ade51d6b290060d0f04a77f011ac29ab52..ca1a9067c52f95de4494eb931ccb4bf760a13f9c 100644 (file)
@@ -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
index ceb8f2d2078fd15f6710ba13ad07e62a9381da40..526187e31bd0485b35cb8b66d768d62f723a713c 100644 (file)
@@ -1930,6 +1930,8 @@ public:
 
   bool isInlineDefinitionExternallyVisible() const;
 
+  bool isMSExternInline() const;
+
   bool doesDeclarationForceExternallyVisibleDefinition() const;
 
   /// isOverloadedOperator - Whether this function declaration
index 699620784ecdcc1210192fdae7741079a54b44b2..247c6e714f471e205916beab1fb201967e72dd05 100644 (file)
@@ -63,7 +63,7 @@ enum GVALinkage {
   GVA_CXXInline,
   GVA_StrongExternal,
   GVA_TemplateInstantiation,
-  GVA_ExplicitTemplateInstantiation
+  GVA_StrongODR
 };
 
 inline bool isExternallyVisible(Linkage L) {
index 5aa4beeb292bbff75ee9b6bd63315129ed995047..3ed2a9ff1cdc52fac8d98e4e4c5fc71c0e8cd843 100644 (file)
@@ -7732,7 +7732,7 @@ QualType ASTContext::GetBuiltinType(unsigned Id,
   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::GetGVALinkageForFunction(const FunctionDecl *FD) {
     break;
 
   case TSK_ExplicitInstantiationDefinition:
-    return GVA_ExplicitTemplateInstantiation;
+    return GVA_StrongODR;
 
   case TSK_ExplicitInstantiationDeclaration:
   case TSK_ImplicitInstantiation:
@@ -7776,6 +7776,12 @@ GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) {
                                        == 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::GetGVALinkageForVariable(const VarDecl *VD) {
   // Fall through to treat this like any other instantiation.
 
   case TSK_ExplicitInstantiationDefinition:
-    return GVA_ExplicitTemplateInstantiation;
+    return GVA_StrongODR;
 
   case TSK_ImplicitInstantiation:
     return GVA_TemplateInstantiation;
index 83cbb44f7f912f21c38c0ff40c23798c13ab3606..13681ddf55982509d5ea52e6ac3773bb04ed27b3 100644 (file)
@@ -2546,6 +2546,37 @@ unsigned FunctionDecl::getMinRequiredArguments() const {
   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 FunctionDecl *Redecl) {
 /// \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::doesDeclarationForceExternallyVisibleDefinition() const {
 
   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.
index d997a79f5b23949c21567d683df1164d64af468a..c26f769118217d993924cb1d901e4750bae79e1e 100644 (file)
@@ -589,7 +589,7 @@ CodeGenModule::getFunctionLinkage(GlobalDecl GD) {
   // 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::GetLLVMLinkageVarDefinition(const VarDecl *D, bool isConstant) {
       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>()) ||
index 70ab696b64ee02044a8090f2997beb82759fd09d..96c9a86baecb659254ae3903be333012aea42aa9 100644 (file)
 
 // 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; }
 
index 7c645148ae6f7f82403d53cf5a44bf80479827c1..622cfa9536f3d2306e7df0471177f3b89730e2ca 100644 (file)
@@ -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(); }
+};