Allow dllimport/dllexport on inline functions and adjust the linkage.
This is a step towards handling these attributes on classes (PR11170).
Differential Revision: http://reviews.llvm.org/D3772
llvm-svn: 208925
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index aa74e1a..2f40616 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -7742,7 +7742,8 @@
return getFunctionType(ResType, ArgTypes, EPI);
}
-GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) const {
+static GVALinkage basicGVALinkageForFunction(const ASTContext &Context,
+ const FunctionDecl *FD) {
if (!FD->isExternallyVisible())
return GVA_Internal;
@@ -7773,8 +7774,11 @@
if (!FD->isInlined())
return External;
- if ((!getLangOpts().CPlusPlus && !getLangOpts().MSVCCompat) ||
+ if ((!Context.getLangOpts().CPlusPlus && !Context.getLangOpts().MSVCCompat &&
+ !FD->hasAttr<DLLExportAttr>()) ||
FD->hasAttr<GNUInlineAttr>()) {
+ // FIXME: This doesn't match gcc's behavior for dllexport inline functions.
+
// GNU or C99 inline semantics. Determine whether this symbol should be
// externally visible.
if (FD->isInlineDefinitionExternallyVisible())
@@ -7793,7 +7797,26 @@
return GVA_DiscardableODR;
}
-GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) {
+static GVALinkage adjustGVALinkageForDLLAttribute(GVALinkage L, const Decl *D) {
+ // See http://msdn.microsoft.com/en-us/library/xa0d9ste.aspx
+ // dllexport/dllimport on inline functions.
+ if (D->hasAttr<DLLImportAttr>()) {
+ if (L == GVA_DiscardableODR || L == GVA_StrongODR)
+ return GVA_AvailableExternally;
+ } else if (D->hasAttr<DLLExportAttr>()) {
+ if (L == GVA_DiscardableODR)
+ return GVA_StrongODR;
+ }
+ return L;
+}
+
+GVALinkage ASTContext::GetGVALinkageForFunction(const FunctionDecl *FD) const {
+ return adjustGVALinkageForDLLAttribute(basicGVALinkageForFunction(*this, FD),
+ FD);
+}
+
+static GVALinkage basicGVALinkageForVariable(const ASTContext &Context,
+ const VarDecl *VD) {
if (!VD->isExternallyVisible())
return GVA_Internal;
@@ -7807,7 +7830,7 @@
// enclosing function.
if (LexicalContext)
StaticLocalLinkage =
- GetGVALinkageForFunction(cast<FunctionDecl>(LexicalContext));
+ Context.GetGVALinkageForFunction(cast<FunctionDecl>(LexicalContext));
// GVA_StrongODR function linkage is stronger than what we need,
// downgrade to GVA_DiscardableODR.
@@ -7821,7 +7844,7 @@
// Itanium-specified entry point, which has the normal linkage of the
// variable.
if (VD->getTLSKind() == VarDecl::TLS_Dynamic &&
- getTargetInfo().getTriple().isMacOSX())
+ Context.getTargetInfo().getTriple().isMacOSX())
return GVA_Internal;
switch (VD->getTemplateSpecializationKind()) {
@@ -7842,6 +7865,11 @@
llvm_unreachable("Invalid Linkage!");
}
+GVALinkage ASTContext::GetGVALinkageForVariable(const VarDecl *VD) {
+ return adjustGVALinkageForDLLAttribute(basicGVALinkageForVariable(*this, VD),
+ VD);
+}
+
bool ASTContext::DeclMustBeEmitted(const Decl *D) {
if (const VarDecl *VD = dyn_cast<VarDecl>(D)) {
if (!VD->isFileVarDecl())
diff --git a/clang/lib/AST/Decl.cpp b/clang/lib/AST/Decl.cpp
index 49466b2d..101b164 100644
--- a/clang/lib/AST/Decl.cpp
+++ b/clang/lib/AST/Decl.cpp
@@ -2572,7 +2572,7 @@
assert(isInlined() && "expected to get called on an inlined function!");
const ASTContext &Context = getASTContext();
- if (!Context.getLangOpts().MSVCCompat)
+ if (!Context.getLangOpts().MSVCCompat && !hasAttr<DLLExportAttr>())
return false;
for (const FunctionDecl *FD = this; FD; FD = FD->getPreviousDecl())
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 25399cc..d9d2eb0 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -1960,15 +1960,6 @@
if (Linkage == GVA_AvailableExternally)
return llvm::Function::AvailableExternallyLinkage;
- // LinkOnceODRLinkage is insufficient if the symbol is required to exist in
- // the symbol table. Promote the linkage to WeakODRLinkage to preserve the
- // semantics of LinkOnceODRLinkage while providing visibility in the symbol
- // table.
- llvm::GlobalValue::LinkageTypes OnceLinkage =
- llvm::GlobalValue::LinkOnceODRLinkage;
- if (D->hasAttr<DLLExportAttr>() || D->hasAttr<DLLImportAttr>())
- OnceLinkage = llvm::GlobalVariable::WeakODRLinkage;
-
// Note that Apple's kernel linker doesn't support symbol
// coalescing, so we need to avoid linkonce and weak linkages there.
// Normally, this means we just map to internal, but for explicit
@@ -1981,7 +1972,7 @@
// merged with other definitions. c) C++ has the ODR, so we know the
// definition is dependable.
if (Linkage == GVA_DiscardableODR)
- return !Context.getLangOpts().AppleKext ? OnceLinkage
+ return !Context.getLangOpts().AppleKext ? llvm::Function::LinkOnceODRLinkage
: llvm::Function::InternalLinkage;
// An explicit instantiation of a template has weak linkage, since
@@ -1995,14 +1986,14 @@
// Destructor variants in the Microsoft C++ ABI are always linkonce_odr thunks
// emitted on an as-needed basis.
if (UseThunkForDtorVariant)
- return OnceLinkage;
+ return llvm::GlobalValue::LinkOnceODRLinkage;
// If required by the ABI, give definitions of static data members with inline
// initializers at least linkonce_odr linkage.
if (getCXXABI().isInlineInitializedStaticDataMemberLinkOnce() &&
isa<VarDecl>(D) &&
isVarDeclInlineInitializedStaticDataMember(cast<VarDecl>(D)))
- return OnceLinkage;
+ return llvm::GlobalValue::LinkOnceODRLinkage;
// C++ doesn't have tentative definitions and thus cannot have common
// linkage.
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 2f434ce..3c19e96 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -9764,20 +9764,12 @@
if (const FunctionProtoType *FPT = FD->getType()->getAs<FunctionProtoType>())
ResolveExceptionSpec(D->getLocation(), FPT);
- // Checking attributes of current function definition
- // dllimport attribute.
- DLLImportAttr *DA = FD->getAttr<DLLImportAttr>();
- if (DA && (!FD->hasAttr<DLLExportAttr>())) {
- // dllimport attribute cannot be directly applied to definition.
- // Microsoft accepts dllimport for functions defined within class scope.
- if (!DA->isInherited() &&
- !(LangOpts.MicrosoftExt && FD->getLexicalDeclContext()->isRecord())) {
- Diag(FD->getLocation(),
- diag::err_attribute_can_be_applied_only_to_symbol_declaration)
- << DA;
- FD->setInvalidDecl();
- return D;
- }
+ // dllimport cannot be applied to non-inline function definitions.
+ if (FD->hasAttr<DLLImportAttr>() && !FD->isInlined()) {
+ assert(!FD->hasAttr<DLLExportAttr>());
+ Diag(FD->getLocation(), diag::err_attribute_dllimport_function_definition);
+ FD->setInvalidDecl();
+ return D;
}
// We want to attach documentation to original Decl (which might be
// a function template).
diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp
index 5ca5a8f..9caf918 100644
--- a/clang/lib/Sema/SemaDeclAttr.cpp
+++ b/clang/lib/Sema/SemaDeclAttr.cpp
@@ -3841,13 +3841,6 @@
return;
}
- // Currently, the dllimport attribute is ignored for inlined functions.
- // Warning is emitted.
- if (FD && FD->isInlineSpecified()) {
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
- return;
- }
-
unsigned Index = Attr.getAttributeSpellingListIndex();
DLLImportAttr *NewAttr = S.mergeDLLImportAttr(D, Attr.getRange(), Index);
if (NewAttr)
@@ -3868,14 +3861,6 @@
}
static void handleDLLExportAttr(Sema &S, Decl *D, const AttributeList &Attr) {
- // Currently, the dllexport attribute is ignored for inlined functions, unless
- // the -fkeep-inline-functions flag has been used. Warning is emitted.
- if (isa<FunctionDecl>(D) && cast<FunctionDecl>(D)->isInlineSpecified()) {
- // FIXME: ... unless the -fkeep-inline-functions flag has been used.
- S.Diag(Attr.getLoc(), diag::warn_attribute_ignored) << Attr.getName();
- return;
- }
-
unsigned Index = Attr.getAttributeSpellingListIndex();
DLLExportAttr *NewAttr = S.mergeDLLExportAttr(D, Attr.getRange(), Index);
if (NewAttr)