[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