Index: cfe/trunk/include/clang/Sema/SemaInternal.h =================================================================== --- cfe/trunk/include/clang/Sema/SemaInternal.h +++ cfe/trunk/include/clang/Sema/SemaInternal.h @@ -74,6 +74,18 @@ Var->markUsed(SemaRef.Context); } + +/// Return a DLL attribute from the declaration. +inline InheritableAttr *getDLLAttr(Decl *D) { + assert(!(D->hasAttr() && D->hasAttr()) && + "A declaration cannot be both dllimport and dllexport."); + if (auto *Import = D->getAttr()) + return Import; + if (auto *Export = D->getAttr()) + return Export; + return nullptr; +} + } #endif Index: cfe/trunk/lib/CodeGen/CGDecl.cpp =================================================================== --- cfe/trunk/lib/CodeGen/CGDecl.cpp +++ cfe/trunk/lib/CodeGen/CGDecl.cpp @@ -201,6 +201,13 @@ if (D.getTLSKind()) CGM.setTLSMode(GV, D); + if (D.isExternallyVisible()) { + if (D.hasAttr()) + GV->setDLLStorageClass(llvm::GlobalVariable::DLLImportStorageClass); + else if (D.hasAttr()) + GV->setDLLStorageClass(llvm::GlobalVariable::DLLExportStorageClass); + } + // Make sure the result is of the correct type. unsigned ExpectedAddrSpace = CGM.getContext().getTargetAddressSpace(Ty); if (AddrSpace != ExpectedAddrSpace) { Index: cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp =================================================================== --- cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp +++ cfe/trunk/lib/CodeGen/MicrosoftCXXABI.cpp @@ -1425,12 +1425,13 @@ Out.flush(); } - // Create the guard variable with a zero-initializer. Just absorb linkage - // and visibility from the guarded variable. + // Create the guard variable with a zero-initializer. Just absorb linkage, + // visibility and dll storage class from the guarded variable. GI->Guard = new llvm::GlobalVariable(CGM.getModule(), GuardTy, false, GV->getLinkage(), Zero, GuardName.str()); GI->Guard->setVisibility(GV->getVisibility()); + GI->Guard->setDLLStorageClass(GV->getDLLStorageClass()); } else { assert(GI->Guard->getLinkage() == GV->getLinkage() && "static local from the same function had different linkage"); Index: cfe/trunk/lib/Sema/SemaDecl.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDecl.cpp +++ cfe/trunk/lib/Sema/SemaDecl.cpp @@ -9097,6 +9097,18 @@ checkAttributesAfterMerging(*this, *VD); + // Static locals inherit dll attributes from their function. + if (VD->isStaticLocal()) { + if (FunctionDecl *FD = + dyn_cast(VD->getParentFunctionOrMethod())) { + if (Attr *A = getDLLAttr(FD)) { + auto *NewAttr = cast(A->clone(getASTContext())); + NewAttr->setInherited(true); + VD->addAttr(NewAttr); + } + } + } + // Imported static data members cannot be defined out-of-line. if (const DLLImportAttr *IA = VD->getAttr()) { if (VD->isStaticDataMember() && VD->isOutOfLine() && Index: cfe/trunk/lib/Sema/SemaDeclCXX.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDeclCXX.cpp +++ cfe/trunk/lib/Sema/SemaDeclCXX.cpp @@ -4347,17 +4347,6 @@ } } -/// \brief Return a DLL attribute from the declaration. -static InheritableAttr *getDLLAttr(Decl *D) { - assert(!(D->hasAttr() && D->hasAttr()) && - "A declaration cannot be both dllimport and dllexport."); - if (auto *Import = D->getAttr()) - return Import; - if (auto *Export = D->getAttr()) - return Export; - return nullptr; -} - /// \brief Check class-level dllimport/dllexport attribute. static void checkDLLAttribute(Sema &S, CXXRecordDecl *Class) { Attr *ClassAttr = getDLLAttr(Class); Index: cfe/trunk/test/CodeGenCXX/dllexport.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/dllexport.cpp +++ cfe/trunk/test/CodeGenCXX/dllexport.cpp @@ -72,6 +72,22 @@ // GNU-DAG: @ExternalAutoTypeGlobal = dllexport global %struct.External zeroinitializer, align 4 __declspec(dllexport) auto ExternalAutoTypeGlobal = External(); +int f(); +// MSC-DAG: @"\01?x@?0??nonInlineStaticLocalsFunc@@YAHXZ@4HA" = internal {{(unnamed_addr )*}}global i32 0 +// MSC-DAG: @"\01?$S1@?0??nonInlineStaticLocalsFunc@@YAHXZ@4IA" = internal {{(unnamed_addr )*}}global i32 0 +int __declspec(dllexport) nonInlineStaticLocalsFunc() { + static int x = f(); + return x++; +}; + +// MSC-DAG: @"\01?x@?1??inlineStaticLocalsFunc@@YAHXZ@4HA" = weak_odr dllexport global i32 0 +// MSC-DAG: @"\01??_B?1??inlineStaticLocalsFunc@@YAHXZ@51" = weak_odr dllexport global i32 0 +// Note: MinGW doesn't seem to export the static local here. +inline int __declspec(dllexport) inlineStaticLocalsFunc() { + static int x = f(); + return x++; +} + //===----------------------------------------------------------------------===// Index: cfe/trunk/test/CodeGenCXX/dllimport.cpp =================================================================== --- cfe/trunk/test/CodeGenCXX/dllimport.cpp +++ cfe/trunk/test/CodeGenCXX/dllimport.cpp @@ -85,6 +85,15 @@ namespace ns { __declspec(dllimport) int ExternalGlobal; } USEVAR(ns::ExternalGlobal) +int f(); +// MO1-DAG: @"\01?x@?1??inlineStaticLocalsFunc@@YAHXZ@4HA" = available_externally dllimport global i32 0 +// MO1-DAG: @"\01??_B?1??inlineStaticLocalsFunc@@YAHXZ@51" = available_externally dllimport global i32 0 +inline int __declspec(dllimport) inlineStaticLocalsFunc() { + static int x = f(); + return x++; +}; +USE(inlineStaticLocalsFunc); + //===----------------------------------------------------------------------===//