Skip to content

Commit 606bd6d

Browse files
committed
Don't dllimport inline functions when targeting MinGW (PR21366)
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
1 parent 42bce8f commit 606bd6d

File tree

11 files changed

+624
-329
lines changed

11 files changed

+624
-329
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2114,8 +2114,14 @@ def err_attribute_aligned_too_great : Error<
21142114
def warn_redeclaration_without_attribute_prev_attribute_ignored : Warning<
21152115
"%q0 redeclared without %1 attribute: previous %1 ignored">,
21162116
InGroup<DiagGroup<"inconsistent-dllimport">>;
2117+
def warn_dllimport_dropped_from_inline_function : Warning<
2118+
"%q0 redeclared inline; %1 attribute ignored">,
2119+
InGroup<IgnoredAttributes>;
21172120
def warn_attribute_ignored : Warning<"%0 attribute ignored">,
21182121
InGroup<IgnoredAttributes>;
2122+
def warn_attribute_ignored_on_inline :
2123+
Warning<"%0 attribute ignored on inline function">,
2124+
InGroup<IgnoredAttributes>;
21192125
def warn_attribute_after_definition_ignored : Warning<
21202126
"attribute %0 after definition is ignored">,
21212127
InGroup<IgnoredAttributes>;

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2003,6 +2003,8 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D) {
20032003
GV->setDLLStorageClass(llvm::GlobalVariable::DLLImportStorageClass);
20042004
else if (D->hasAttr<DLLExportAttr>())
20052005
GV->setDLLStorageClass(llvm::GlobalVariable::DLLExportStorageClass);
2006+
else
2007+
GV->setDLLStorageClass(llvm::GlobalVariable::DefaultStorageClass);
20062008

20072009
if (Linkage == llvm::GlobalVariable::CommonLinkage)
20082010
// common vars aren't constant even if declared const.
@@ -2338,6 +2340,12 @@ void CodeGenModule::EmitGlobalFunctionDefinition(GlobalDecl GD,
23382340
// declarations).
23392341
auto *Fn = cast<llvm::Function>(GV);
23402342
setFunctionLinkage(GD, Fn);
2343+
if (D->hasAttr<DLLImportAttr>())
2344+
GV->setDLLStorageClass(llvm::GlobalVariable::DLLImportStorageClass);
2345+
else if (D->hasAttr<DLLExportAttr>())
2346+
GV->setDLLStorageClass(llvm::GlobalVariable::DLLExportStorageClass);
2347+
else
2348+
GV->setDLLStorageClass(llvm::GlobalVariable::DefaultStorageClass);
23412349

23422350
// FIXME: this is redundant with part of setFunctionDefinitionAttributes
23432351
setGlobalVisibility(Fn, D);

clang/lib/Sema/SemaDecl.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5185,6 +5185,14 @@ static void checkDLLAttributeRedeclaration(Sema &S, NamedDecl *OldDecl,
51855185
S.Diag(OldImportAttr->getLocation(), diag::note_previous_attribute);
51865186
OldDecl->dropAttr<DLLImportAttr>();
51875187
NewDecl->dropAttr<DLLImportAttr>();
5188+
} else if (IsInline && OldImportAttr &&
5189+
!S.Context.getTargetInfo().getCXXABI().isMicrosoft()) {
5190+
// In MinGW, seeing a function declared inline drops the dllimport attribute.
5191+
OldDecl->dropAttr<DLLImportAttr>();
5192+
NewDecl->dropAttr<DLLImportAttr>();
5193+
S.Diag(NewDecl->getLocation(),
5194+
diag::warn_dllimport_dropped_from_inline_function)
5195+
<< NewDecl << OldImportAttr;
51885196
}
51895197
}
51905198

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3999,6 +3999,16 @@ static void handleDLLAttr(Sema &S, Decl *D, const AttributeList &A) {
39993999
return;
40004000
}
40014001

4002+
if (FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) {
4003+
if (FD->isInlined() && A.getKind() == AttributeList::AT_DLLImport &&
4004+
!S.Context.getTargetInfo().getCXXABI().isMicrosoft()) {
4005+
// MinGW doesn't allow dllimport on inline functions.
4006+
S.Diag(A.getRange().getBegin(), diag::warn_attribute_ignored_on_inline)
4007+
<< A.getName();
4008+
return;
4009+
}
4010+
}
4011+
40024012
unsigned Index = A.getAttributeSpellingListIndex();
40034013
Attr *NewAttr = A.getKind() == AttributeList::AT_DLLExport
40044014
? (Attr *)S.mergeDLLExportAttr(D, A.getRange(), Index)

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4655,7 +4655,9 @@ static void checkDLLAttribute(Sema &S, CXXRecordDecl *Class) {
46554655
// Don't inherit dll attribute until the template is instantiated.
46564656
return;
46574657

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

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

4677-
// Don't process deleted methods.
4678-
if (MD && MD->isDeleted())
4679-
continue;
4679+
if (MD) {
4680+
// Don't process deleted methods.
4681+
if (MD->isDeleted())
4682+
continue;
46804683

4681-
if (MD && MD->isMoveAssignmentOperator() && !ClassExported &&
4682-
MD->isInlined()) {
4683-
// Current MSVC versions don't export the move assignment operators, so
4684-
// don't attempt to import them if we have a definition.
4685-
continue;
4684+
if (MD->isMoveAssignmentOperator() && ClassImported && MD->isInlined()) {
4685+
// Current MSVC versions don't export the move assignment operators, so
4686+
// don't attempt to import them if we have a definition.
4687+
continue;
4688+
}
4689+
4690+
if (MD->isInlined() && ClassImported &&
4691+
!S.Context.getTargetInfo().getCXXABI().isMicrosoft()) {
4692+
// MinGW does not import inline functions.
4693+
continue;
4694+
}
46864695
}
46874696

46884697
if (!getDLLAttr(Member)) {

clang/test/CodeGen/dllimport.c

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -std=c11 -O0 -o - %s | FileCheck %s
2-
// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-llvm -std=c11 -O0 -o - %s | FileCheck %s
3-
// RUN: %clang_cc1 -triple i686-windows-gnu -emit-llvm -std=c11 -O0 -o - %s | FileCheck %s
4-
// RUN: %clang_cc1 -triple x86_64-windows-gnu -emit-llvm -std=c11 -O0 -o - %s | FileCheck %s
5-
// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -std=c11 -O1 -o - %s | FileCheck --check-prefix=O1 %s
6-
// RUN: %clang_cc1 -triple i686-windows-gnu -emit-llvm -std=c11 -O1 -o - %s | FileCheck --check-prefix=O1 %s
1+
// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -std=c11 -O0 -o - %s | FileCheck --check-prefix=CHECK --check-prefix=MS %s
2+
// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-llvm -std=c11 -O0 -o - %s | FileCheck --check-prefix=CHECK --check-prefix=MS %s
3+
// RUN: %clang_cc1 -triple i686-windows-gnu -emit-llvm -std=c11 -O0 -o - %s | FileCheck --check-prefix=CHECK --check-prefix=GNU %s
4+
// RUN: %clang_cc1 -triple x86_64-windows-gnu -emit-llvm -std=c11 -O0 -o - %s | FileCheck --check-prefix=CHECK --check-prefix=GNU %s
5+
// RUN: %clang_cc1 -triple i686-windows-msvc -emit-llvm -std=c11 -O1 -o - %s | FileCheck --check-prefix=O1 --check-prefix=MO1 %s
6+
// RUN: %clang_cc1 -triple i686-windows-gnu -emit-llvm -std=c11 -O1 -o - %s | FileCheck --check-prefix=O1 --check-prefix=GO1 %s
77

88
#define JOIN2(x, y) x##y
99
#define JOIN(x, y) JOIN2(x, y)
@@ -79,14 +79,18 @@ __declspec(dllimport) void decl(void);
7979
void (*use_decl)(void) = &decl;
8080

8181
// Import inline function.
82-
// CHECK-DAG: declare dllimport void @inlineFunc()
83-
// O1-DAG: define available_externally dllimport void @inlineFunc()
82+
// MS-DAG: declare dllimport void @inlineFunc()
83+
// MO1-DAG: define available_externally dllimport void @inlineFunc()
84+
// GNU-DAG: declare void @inlineFunc()
85+
// GO1-DAG: define available_externally void @inlineFunc()
8486
__declspec(dllimport) inline void inlineFunc(void) {}
8587
USE(inlineFunc)
8688

8789
// inline attributes
88-
// CHECK-DAG: declare dllimport void @noinline()
89-
// O1-DAG: define available_externally dllimport void @noinline()
90+
// MS-DAG: declare dllimport void @noinline()
91+
// MO1-DAG: define available_externally dllimport void @noinline()
92+
// GNU-DAG: declare void @noinline()
93+
// GO1-DAG: define available_externally void @noinline()
9094
// CHECK-NOT: @alwaysInline()
9195
// O1-NOT: @alwaysInline()
9296
__declspec(dllimport) __attribute__((noinline)) inline void noinline(void) {}

clang/test/CodeGenCXX/dllexport.cpp

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -594,7 +594,8 @@ USEMEMFUNC(PartiallySpecializedExportedClassTemplate<void*>, f);
594594

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

622623
template <typename T> struct ClassTemplate { void func() {} };
623624
template <typename T> struct __declspec(dllexport) ExportedClassTemplate { void func() {} };
624-
template <typename T> struct __declspec(dllimport) ImportedClassTemplate { void func() {} };
625+
template <typename T> struct __declspec(dllimport) ImportedClassTemplate { void func(); };
626+
template <typename T> void ImportedClassTemplate<T>::func() {}
625627

626628
template <typename T> struct ExplicitlySpecializedTemplate { void func() {} };
627629
template <> struct ExplicitlySpecializedTemplate<int> { void func() {} };
628630
template <typename T> struct ExplicitlyExportSpecializedTemplate { void func() {} };
629631
template <> struct __declspec(dllexport) ExplicitlyExportSpecializedTemplate<int> { void func() {} };
630-
template <typename T> struct ExplicitlyImportSpecializedTemplate { void func() {} };
631-
template <> struct __declspec(dllimport) ExplicitlyImportSpecializedTemplate<int> { void func() {} };
632+
template <typename T> struct ExplicitlyImportSpecializedTemplate { void func(); };
633+
template <> struct __declspec(dllimport) ExplicitlyImportSpecializedTemplate<int> { void func(); };
632634

633635
template <typename T> struct ExplicitlyInstantiatedTemplate { void func() {} };
634636
template struct ExplicitlyInstantiatedTemplate<int>;
635637
template <typename T> struct ExplicitlyExportInstantiatedTemplate { void func() {} };
636638
template struct __declspec(dllexport) ExplicitlyExportInstantiatedTemplate<int>;
637-
template <typename T> struct ExplicitlyImportInstantiatedTemplate { void func() {} };
639+
template <typename T> struct ExplicitlyImportInstantiatedTemplate { void func(); };
638640
template struct __declspec(dllimport) ExplicitlyImportInstantiatedTemplate<int>;
639641

640642

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

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

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

0 commit comments

Comments
 (0)