Skip to content

Commit

Permalink
Don't dllimport inline functions when targeting MinGW (PR21366)
Browse files Browse the repository at this point in the history
It turns out that MinGW never dllimports of exports inline functions.
This means that code compiled with Clang would fail to link with
MinGW-compiled libraries since we might try to import functions that
are not imported.

To fix this, make Clang never dllimport inline functions when targeting
MinGW.

llvm-svn: 221154
  • Loading branch information
zmodem committed Nov 3, 2014
1 parent 42bce8f commit 606bd6d
Show file tree
Hide file tree
Showing 11 changed files with 624 additions and 329 deletions.
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -2114,8 +2114,14 @@ def err_attribute_aligned_too_great : Error<
def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning<
"%q0 redeclared without %1 attribute: previous %1 ignored">,
InGroup<DiagGroup<"inconsistent-dllimport">>;
def warn_dllimport_dropped_from_inline_function : Warning<
"%q0 redeclared inline; %1 attribute ignored">,
InGroup<IgnoredAttributes>;
def warn_attribute_ignored : Warning<"%0 attribute ignored">,
InGroup<IgnoredAttributes>;
def warn_attribute_ignored_on_inline :
Warning<"%0 attribute ignored on inline function">,
InGroup<IgnoredAttributes>;
def warn_attribute_after_definition_ignored : Warning<
"attribute %0 after definition is ignored">,
InGroup<IgnoredAttributes>;
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/CodeGen/CodeGenModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2003,6 +2003,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
GV->setDLLStorageClass(llvm::GlobalVariable::DLLImportStorageClass);
else if (D->hasAttr<DLLExportAttr>())
GV->setDLLStorageClass(llvm::GlobalVariable::DLLExportStorageClass);
else
GV->setDLLStorageClass(llvm::GlobalVariable::DefaultStorageClass);

if (Linkage == llvm::GlobalVariable::CommonLinkage)
// common vars aren't constant even if declared const.
Expand Down Expand Up @@ -2338,6 +2340,12 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD,
// declarations).
auto *Fn = cast<llvm::Function>(GV);
setFunctionLinkage(GD, Fn);
if (D->hasAttr<DLLImportAttr>())
GV->setDLLStorageClass(llvm::GlobalVariable::DLLImportStorageClass);
else if (D->hasAttr<DLLExportAttr>())
GV->setDLLStorageClass(llvm::GlobalVariable::DLLExportStorageClass);
else
GV->setDLLStorageClass(llvm::GlobalVariable::DefaultStorageClass);

// FIXME: this is redundant with part of setFunctionDefinitionAttributes
setGlobalVisibility(Fn, D);
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5185,6 +5185,14 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl,
S.Diag(OldImportAttr->getLocation(), diag::note_previous_attribute);
OldDecl->dropAttr<DLLImportAttr>();
NewDecl->dropAttr<DLLImportAttr>();
} else if (IsInline && OldImportAttr &&
!S.Context.getTargetInfo().getCXXABI().isMicrosoft()) {
// In MinGW, seeing a function declared inline drops the dllimport attribute.
OldDecl->dropAttr<DLLImportAttr>();
NewDecl->dropAttr<DLLImportAttr>();
S.Diag(NewDecl->getLocation(),
diag::warn_dllimport_dropped_from_inline_function)
<< NewDecl << OldImportAttr;
}
}

Expand Down
10 changes: 10 additions & 0 deletions clang/lib/Sema/SemaDeclAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3999,6 +3999,16 @@ static void handleDLLAttr(Sema &S, Decl *D, const AttributeList &A) {
return;
}

if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
if (FD->isInlined() && A.getKind() == AttributeList::AT_DLLImport &&
!S.Context.getTargetInfo().getCXXABI().isMicrosoft()) {
// MinGW doesn't allow dllimport on inline functions.
S.Diag(A.getRange().getBegin(), diag::warn_attribute_ignored_on_inline)
<< A.getName();
return;
}
}

unsigned Index = A.getAttributeSpellingListIndex();
Attr *NewAttr = A.getKind() == AttributeList::AT_DLLExport
? (Attr *)S.mergeDLLExportAttr(D, A.getRange(), Index)
Expand Down
27 changes: 18 additions & 9 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4655,7 +4655,9 @@ static void checkDLLAttribute(Sema &S, CXXRecordDecl *Class) {
// Don't inherit dll attribute until the template is instantiated.
return;

bool ClassExported = ClassAttr->getKind() == attr::DLLExport;
// The class is either imported or exported.
const bool ClassExported = ClassAttr->getKind() == attr::DLLExport;
const bool ClassImported = !ClassExported;

// Force declaration of implicit members so they can inherit the attribute.
S.ForceDeclarationOfImplicitMembers(Class);
Expand All @@ -4674,15 +4676,22 @@ static void checkDLLAttribute(Sema &S, CXXRecordDecl *Class) {
if (!VD && !MD)
continue;

// Don't process deleted methods.
if (MD && MD->isDeleted())
continue;
if (MD) {
// Don't process deleted methods.
if (MD->isDeleted())
continue;

if (MD && MD->isMoveAssignmentOperator() && !ClassExported &&
MD->isInlined()) {
// Current MSVC versions don't export the move assignment operators, so
// don't attempt to import them if we have a definition.
continue;
if (MD->isMoveAssignmentOperator() && ClassImported && MD->isInlined()) {
// Current MSVC versions don't export the move assignment operators, so
// don't attempt to import them if we have a definition.
continue;
}

if (MD->isInlined() && ClassImported &&
!S.Context.getTargetInfo().getCXXABI().isMicrosoft()) {
// MinGW does not import inline functions.
continue;
}
}

if (!getDLLAttr(Member)) {
Expand Down
24 changes: 14 additions & 10 deletions clang/test/CodeGen/dllimport.c
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -std=c11 -O0 -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-llvm -std=c11 -O0 -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple i686-windows-gnu -emit-llvm -std=c11 -O0 -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-windows-gnu -emit-llvm -std=c11 -O0 -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -std=c11 -O1 -o - %s | FileCheck --check-prefix=O1 %s
// RUN: %clang_cc1 -triple i686-windows-gnu -emit-llvm -std=c11 -O1 -o - %s | FileCheck --check-prefix=O1 %s
// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -std=c11 -O0 -o - %s | FileCheck --check-prefix=CHECK --check-prefix=MS %s
// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-llvm -std=c11 -O0 -o - %s | FileCheck --check-prefix=CHECK --check-prefix=MS %s
// RUN: %clang_cc1 -triple i686-windows-gnu -emit-llvm -std=c11 -O0 -o - %s | FileCheck --check-prefix=CHECK --check-prefix=GNU %s
// RUN: %clang_cc1 -triple x86_64-windows-gnu -emit-llvm -std=c11 -O0 -o - %s | FileCheck --check-prefix=CHECK --check-prefix=GNU %s
// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -std=c11 -O1 -o - %s | FileCheck --check-prefix=O1 --check-prefix=MO1 %s
// RUN: %clang_cc1 -triple i686-windows-gnu -emit-llvm -std=c11 -O1 -o - %s | FileCheck --check-prefix=O1 --check-prefix=GO1 %s

#define JOIN2(x, y) x##y
#define JOIN(x, y) JOIN2(x, y)
Expand Down Expand Up @@ -79,14 +79,18 @@ __declspec(dllimport) void decl(void);
void (*use_decl)(void) = &decl;

// Import inline function.
// CHECK-DAG: declare dllimport void @inlineFunc()
// O1-DAG: define available_externally dllimport void @inlineFunc()
// MS-DAG: declare dllimport void @inlineFunc()
// MO1-DAG: define available_externally dllimport void @inlineFunc()
// GNU-DAG: declare void @inlineFunc()
// GO1-DAG: define available_externally void @inlineFunc()
__declspec(dllimport) inline void inlineFunc(void) {}
USE(inlineFunc)

// inline attributes
// CHECK-DAG: declare dllimport void @noinline()
// O1-DAG: define available_externally dllimport void @noinline()
// MS-DAG: declare dllimport void @noinline()
// MO1-DAG: define available_externally dllimport void @noinline()
// GNU-DAG: declare void @noinline()
// GO1-DAG: define available_externally void @noinline()
// CHECK-NOT: @alwaysInline()
// O1-NOT: @alwaysInline()
__declspec(dllimport) __attribute__((noinline)) inline void noinline(void) {}
Expand Down
20 changes: 11 additions & 9 deletions clang/test/CodeGenCXX/dllexport.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,8 @@ USEMEMFUNC(PartiallySpecializedExportedClassTemplate<void*>, f);

// MS ignores DLL attributes on partial specializations; inheritance still works though.
template <typename T> struct __declspec(dllexport) PartiallySpecializedExportedClassTemplate2 {};
template <typename T> struct __declspec(dllimport) PartiallySpecializedExportedClassTemplate2<T*> { void f() {} };
template <typename T> struct __declspec(dllimport) PartiallySpecializedExportedClassTemplate2<T*> { void f(); };
template <typename T> void PartiallySpecializedExportedClassTemplate2<T*>::f() {}
USEMEMFUNC(PartiallySpecializedExportedClassTemplate2<void*>, f);
// M32-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?f@?$PartiallySpecializedExportedClassTemplate2@PAX@@QAEXXZ"
// G32-DAG: declare dllimport x86_thiscallcc void @_ZN42PartiallySpecializedExportedClassTemplate2IPvE1fEv
Expand All @@ -621,20 +622,21 @@ struct __declspec(dllexport) ExportedDerivedClass : NonExportedBaseClass {};

template <typename T> struct ClassTemplate { void func() {} };
template <typename T> struct __declspec(dllexport) ExportedClassTemplate { void func() {} };
template <typename T> struct __declspec(dllimport) ImportedClassTemplate { void func() {} };
template <typename T> struct __declspec(dllimport) ImportedClassTemplate { void func(); };
template <typename T> void ImportedClassTemplate<T>::func() {}

template <typename T> struct ExplicitlySpecializedTemplate { void func() {} };
template <> struct ExplicitlySpecializedTemplate<int> { void func() {} };
template <typename T> struct ExplicitlyExportSpecializedTemplate { void func() {} };
template <> struct __declspec(dllexport) ExplicitlyExportSpecializedTemplate<int> { void func() {} };
template <typename T> struct ExplicitlyImportSpecializedTemplate { void func() {} };
template <> struct __declspec(dllimport) ExplicitlyImportSpecializedTemplate<int> { void func() {} };
template <typename T> struct ExplicitlyImportSpecializedTemplate { void func(); };
template <> struct __declspec(dllimport) ExplicitlyImportSpecializedTemplate<int> { void func(); };

template <typename T> struct ExplicitlyInstantiatedTemplate { void func() {} };
template struct ExplicitlyInstantiatedTemplate<int>;
template <typename T> struct ExplicitlyExportInstantiatedTemplate { void func() {} };
template struct __declspec(dllexport) ExplicitlyExportInstantiatedTemplate<int>;
template <typename T> struct ExplicitlyImportInstantiatedTemplate { void func() {} };
template <typename T> struct ExplicitlyImportInstantiatedTemplate { void func(); };
template struct __declspec(dllimport) ExplicitlyImportInstantiatedTemplate<int>;


Expand Down Expand Up @@ -685,8 +687,8 @@ USEMEMFUNC(DerivedFromExplicitlyExportSpecializedTemplate, func)
// Base class already specialized with import attribute.
struct __declspec(dllexport) DerivedFromExplicitlyImportSpecializedTemplate : public ExplicitlyImportSpecializedTemplate<int> {};
USEMEMFUNC(DerivedFromExplicitlyImportSpecializedTemplate, func)
// M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @"\01?func@?$ExplicitlyImportSpecializedTemplate@H@@QAEXXZ"
// G32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @_ZN35ExplicitlyImportSpecializedTemplateIiE4funcEv
// M32-DAG: declare dllimport x86_thiscallcc void @"\01?func@?$ExplicitlyImportSpecializedTemplate@H@@QAEXXZ"
// G32-DAG: declare dllimport x86_thiscallcc void @_ZN35ExplicitlyImportSpecializedTemplateIiE4funcEv

// Base class already instantiated without dll attribute.
struct __declspec(dllexport) DerivedFromExplicitlyInstantiatedTemplate : public ExplicitlyInstantiatedTemplate<int> {};
Expand All @@ -703,8 +705,8 @@ USEMEMFUNC(DerivedFromExplicitlyExportInstantiatedTemplate, func)
// Base class already instantiated with import attribute.
struct __declspec(dllexport) DerivedFromExplicitlyImportInstantiatedTemplate : public ExplicitlyImportInstantiatedTemplate<int> {};
USEMEMFUNC(DerivedFromExplicitlyImportInstantiatedTemplate, func)
// M32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @"\01?func@?$ExplicitlyImportInstantiatedTemplate@H@@QAEXXZ"
// G32-DAG: {{declare|define available_externally}} dllimport x86_thiscallcc void @_ZN36ExplicitlyImportInstantiatedTemplateIiE4funcEv
// M32-DAG: declare dllimport x86_thiscallcc void @"\01?func@?$ExplicitlyImportInstantiatedTemplate@H@@QAEXXZ"
// G32-DAG: declare dllimport x86_thiscallcc void @_ZN36ExplicitlyImportInstantiatedTemplateIiE4funcEv

// MS: A dll attribute propagates through multiple levels of instantiation.
template <typename T> struct TopClass { void func() {} };
Expand Down

0 comments on commit 606bd6d

Please sign in to comment.