Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -2091,6 +2091,8 @@ InGroup; def err_attribute_dll_redeclaration : Error< "redeclaration of %q0 cannot add %q1 attribute">; +def err_attribute_dllimport_function_definition : Error< + "dllimport cannot by applied to non-inline function definition">; def err_attribute_dllimport_data_definition : Error< "definition of dllimport data">; def err_attribute_weakref_not_static : Error< Index: lib/CodeGen/CodeGenModule.cpp =================================================================== --- lib/CodeGen/CodeGenModule.cpp +++ lib/CodeGen/CodeGenModule.cpp @@ -1960,14 +1960,16 @@ 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() || D->hasAttr()) - OnceLinkage = llvm::GlobalVariable::WeakODRLinkage; + auto DiscardableODRLinkage = llvm::GlobalValue::LinkOnceODRLinkage; + auto NonDiscardableODRLinkage = llvm::GlobalValue::WeakODRLinkage; + + if (D->hasAttr()) { + DiscardableODRLinkage = llvm::GlobalVariable::WeakODRLinkage; + NonDiscardableODRLinkage = llvm::GlobalVariable::WeakODRLinkage; + } else if (D->hasAttr()) { + DiscardableODRLinkage = llvm::GlobalVariable::AvailableExternallyLinkage; + NonDiscardableODRLinkage = llvm::GlobalVariable::AvailableExternallyLinkage; + } // Note that Apple's kernel linker doesn't support symbol // coalescing, so we need to avoid linkonce and weak linkages there. @@ -1981,7 +1983,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 ? DiscardableODRLinkage : llvm::Function::InternalLinkage; // An explicit instantiation of a template has weak linkage, since @@ -1989,20 +1991,20 @@ // and must all be equivalent. However, we are not allowed to // throw away these explicit instantiations. if (Linkage == GVA_StrongODR) - return !Context.getLangOpts().AppleKext ? llvm::Function::WeakODRLinkage + return !Context.getLangOpts().AppleKext ? NonDiscardableODRLinkage : llvm::Function::ExternalLinkage; // Destructor variants in the Microsoft C++ ABI are always linkonce_odr thunks // emitted on an as-needed basis. if (UseThunkForDtorVariant) - return OnceLinkage; + return llvm::GlobalVariable::LinkOnceODRLinkage; // If required by the ABI, give definitions of static data members with inline // initializers at least linkonce_odr linkage. if (getCXXABI().isInlineInitializedStaticDataMemberLinkOnce() && isa(D) && isVarDeclInlineInitializedStaticDataMember(cast(D))) - return OnceLinkage; + return DiscardableODRLinkage; // C++ doesn't have tentative definitions and thus cannot have common // linkage. Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -9770,11 +9770,9 @@ if (DA && (!FD->hasAttr())) { // 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; + + if (!DA->isInherited() && !FD->isInlined()) { + Diag(FD->getLocation(), diag::err_attribute_dllimport_function_definition); FD->setInvalidDecl(); return D; } Index: lib/Sema/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ 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(D) && cast(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) Index: test/CodeGen/dllexport.cpp =================================================================== --- /dev/null +++ test/CodeGen/dllexport.cpp @@ -0,0 +1,25 @@ +// RUN: %clang_cc1 -triple i686-pc-win32 -x c++ -O2 -disable-llvm-optzns -emit-llvm < %s | FileCheck %s + +#define DLLEXPORT __declspec(dllexport) + +void DLLEXPORT a(); +// CHECK-DAG: declare dllexport void @"\01?a@@YAXXZ"() + +inline void DLLEXPORT b() {} +// CHECK-DAG: define weak_odr dllexport void @"\01?b@@YAXXZ"() + +template void c() {} +template void DLLEXPORT c(); +// CHECK-DAG: define weak_odr dllexport void @"\01??$c@H@@YAXXZ"() + +struct S { + void DLLEXPORT a() {} + // CHECK-DAG: define weak_odr dllexport x86_thiscallcc void @"\01?a@S@@QAEXXZ" +}; + +void user() { + // FIXME: dllexported functions must be emitted even if they're not referenced in this TU. + a(); + b(); + &S::a; +} Index: test/CodeGen/dllimport.cpp =================================================================== --- /dev/null +++ test/CodeGen/dllimport.cpp @@ -0,0 +1,24 @@ +// RUN: %clang_cc1 -triple i686-pc-win32 -x c++ -O2 -disable-llvm-optzns -emit-llvm < %s | FileCheck %s + +#define DLLIMPORT __declspec(dllimport) + +void DLLIMPORT a(); +// CHECK-DAG: declare dllimport void @"\01?a@@YAXXZ"() + +inline void DLLIMPORT b() {} +// CHECK-DAG: define available_externally dllimport void @"\01?b@@YAXXZ"() + +template inline void c() {} // FIXME: MSVC accepts this without 'inline' too. +template void DLLIMPORT c(); +// CHECK-DAG: define available_externally dllimport void @"\01??$c@H@@YAXXZ"() + +struct S { + void DLLIMPORT a() {} + // CHECK-DAG: define available_externally dllimport x86_thiscallcc void @"\01?a@S@@QAEXXZ" +}; + +void user(S* s) { + a(); + b(); + s->a(); +} Index: test/Sema/dllexport.c =================================================================== --- test/Sema/dllexport.c +++ test/Sema/dllexport.c @@ -69,10 +69,10 @@ __declspec(dllexport) void def() {} // Export inline function. -__declspec(dllexport) inline void inlineFunc1() {} // expected-warning{{'dllexport' attribute ignored}} +__declspec(dllexport) inline void inlineFunc1() {} extern void inlineFunc1(); -inline void __attribute__((dllexport)) inlineFunc2() {} // expected-warning{{'dllexport' attribute ignored}} +inline void __attribute__((dllexport)) inlineFunc2() {} extern void inlineFunc2(); // Redeclarations Index: test/Sema/dllimport.c =================================================================== --- test/Sema/dllimport.c +++ test/Sema/dllimport.c @@ -97,11 +97,11 @@ void __declspec(dllimport) decl2B(); // Not allowed on function definitions. -__declspec(dllimport) void def() {} // expected-error{{'dllimport' attribute can be applied only to symbol declaration}} +__declspec(dllimport) void def() {} // expected-error{{dllimport cannot by applied to non-inline function definition}} // Import inline function. -__declspec(dllimport) inline void inlineFunc1() {} // expected-warning{{'dllimport' attribute ignored}} -inline void __attribute__((dllimport)) inlineFunc2() {} // expected-warning{{'dllimport' attribute ignored}} +__declspec(dllimport) inline void inlineFunc1() {} +inline void __attribute__((dllimport)) inlineFunc2() {} // Redeclarations __declspec(dllimport) void redecl1(); Index: test/SemaCXX/MicrosoftExtensions.cpp =================================================================== --- test/SemaCXX/MicrosoftExtensions.cpp +++ test/SemaCXX/MicrosoftExtensions.cpp @@ -122,7 +122,7 @@ void f2(void); // expected-note{{previous declaration is here}} }; -__declspec(dllimport) void AAA::f2(void) { // expected-error{{'dllimport' attribute can be applied only to symbol}} +__declspec(dllimport) void AAA::f2(void) { // expected-error{{dllimport cannot by applied to non-inline function definition}} // expected-error@-1{{redeclaration of 'AAA::f2' cannot add 'dllimport' attribute}} } Index: test/SemaCXX/dllexport.cpp =================================================================== --- test/SemaCXX/dllexport.cpp +++ test/SemaCXX/dllexport.cpp @@ -92,10 +92,10 @@ extern "C" __declspec(dllexport) void externC() {} // Export inline function. -__declspec(dllexport) inline void inlineFunc1() {} // expected-warning{{'dllexport' attribute ignored}} -inline void __attribute__((dllexport)) inlineFunc2() {} // expected-warning{{'dllexport' attribute ignored}} +__declspec(dllexport) inline void inlineFunc1() {} +inline void __attribute__((dllexport)) inlineFunc2() {} -__declspec(dllexport) inline void inlineDecl(); // expected-warning{{'dllexport' attribute ignored}} +__declspec(dllexport) inline void inlineDecl(); void inlineDecl() {} __declspec(dllexport) void inlineDef(); @@ -188,7 +188,7 @@ // Export specialization of an exported function template. template<> __declspec(dllexport) void exportedFuncTmpl(); template<> __declspec(dllexport) void exportedFuncTmpl() {} -template<> __declspec(dllexport) inline void exportedFuncTmpl() {} // expected-warning{{'dllexport' attribute ignored}} +template<> __declspec(dllexport) inline void exportedFuncTmpl() {} // Not exporting specialization of an exported function template without // explicit dllexport. @@ -205,7 +205,7 @@ // Export specialization of a non-exported function template. template<> __declspec(dllexport) void funcTmpl(); template<> __declspec(dllexport) void funcTmpl() {} -template<> __declspec(dllexport) inline void funcTmpl() {} // expected-warning{{'dllexport' attribute ignored}} +template<> __declspec(dllexport) inline void funcTmpl() {} Index: test/SemaCXX/dllimport.cpp =================================================================== --- test/SemaCXX/dllimport.cpp +++ test/SemaCXX/dllimport.cpp @@ -116,14 +116,14 @@ void __declspec(dllimport) decl2B(); // Not allowed on function definitions. -__declspec(dllimport) void def() {} // expected-error{{'dllimport' attribute can be applied only to symbol declaration}} +__declspec(dllimport) void def() {} // expected-error{{dllimport cannot by applied to non-inline function definition}} // extern "C" extern "C" __declspec(dllexport) void externC(); // Import inline function. -__declspec(dllimport) inline void inlineFunc1() {} // expected-warning{{'dllimport' attribute ignored}} -inline void __attribute__((dllimport)) inlineFunc2() {} // expected-warning{{'dllimport' attribute ignored}} +__declspec(dllimport) inline void inlineFunc1() {} +inline void __attribute__((dllimport)) inlineFunc2() {} // Redeclarations __declspec(dllimport) void redecl1(); @@ -209,8 +209,8 @@ // Import specialization of an imported function template. A definition must be // declared inline. template<> __declspec(dllimport) void importedFuncTmpl(); -template<> __declspec(dllimport) void importedFuncTmpl() {} // expected-error{{'dllimport' attribute can be applied only to symbol declaration}} -template<> __declspec(dllimport) inline void importedFuncTmpl() {} // expected-warning{{'dllimport' attribute ignored}} +template<> __declspec(dllimport) void importedFuncTmpl() {} // expected-error{{dllimport cannot by applied to non-inline function definition}} +template<> __declspec(dllimport) inline void importedFuncTmpl() {} // Not importing specialization of an imported function template without // explicit dllimport. @@ -223,5 +223,5 @@ // Import specialization of a non-imported function template. A definition must // be declared inline. template<> __declspec(dllimport) void funcTmpl(); -template<> __declspec(dllimport) void funcTmpl() {} // expected-error{{'dllimport' attribute can be applied only to symbol declaration}} -template<> __declspec(dllimport) inline void funcTmpl() {} // expected-warning{{'dllimport' attribute ignored}} +template<> __declspec(dllimport) void funcTmpl() {} // expected-error{{dllimport cannot by applied to non-inline function definition}} +template<> __declspec(dllimport) inline void funcTmpl() {}