[PATCH] Windows support for ObjC DLLIMPORT
Aaron Ballman via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 5 08:54:05 PDT 2016
On Mon, Apr 4, 2016 at 3:34 PM, Wes Witt via cfe-commits
<cfe-commits at lists.llvm.org> wrote:
> Please accept this diff as a change to support dllimport of objective c
> interfaces on windows. I’ve included a new test and changes to an existing
> test as well. All clang tests pass on Linux & Windows. This change is
> required for Microsoft’s use of the clang compiler in support of objective c
> on windows.
Thank you for working on this! Some comments below:
> diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td
> index c7a797c..dc22b27 100644
> --- a/include/clang/Basic/Attr.td
> +++ b/include/clang/Basic/Attr.td
> @@ -2023,7 +2023,8 @@ def DLLExport : InheritableAttr, TargetSpecificAttr<TargetWindows> {
>
> def DLLImport : InheritableAttr, TargetSpecificAttr<TargetWindows> {
> let Spellings = [Declspec<"dllimport">, GCC<"dllimport">];
> - let Subjects = SubjectList<[Function, Var, CXXRecord]>;
> + let Subjects = SubjectList<[Function, Var, CXXRecord, ObjCInterface], WarnDiag,
> + "ExpectedFunctionVariableOrClass">;
The diagnostic for this won't indicate that it's also okay to play on
an Objective-C interface decl; is that intentional?
> let Documentation = [Undocumented];
It would be nice to add some documentation to this, instead of leaving
it totally undocumented. The docs can basically point to MSDN on
__declspec(dllimport), but this would be a good place to let users
know about the Objective-C behavior as well.
> }
>
> diff --git a/lib/CodeGen/CGBlocks.cpp b/lib/CodeGen/CGBlocks.cpp
> index ea164aa..9d2b2f9 100644
> --- a/lib/CodeGen/CGBlocks.cpp
> +++ b/lib/CodeGen/CGBlocks.cpp
> @@ -2334,5 +2334,9 @@ llvm::Constant *CodeGenModule::getNSConcreteStackBlock() {
> Int8PtrTy->getPointerTo(),
> nullptr);
> configureBlocksRuntimeObject(*this, NSConcreteStackBlock);
> + if (getContext().getLangOpts().MSVCCompat) {
> + auto *GV = cast<llvm::GlobalValue>(NSConcreteStackBlock->stripPointerCasts());
> + GV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
> + }
> return NSConcreteStackBlock;
> }
> diff --git a/lib/CodeGen/CGObjCGNU.cpp b/lib/CodeGen/CGObjCGNU.cpp
> index bbe1b8b..dcb3a7d 100644
> --- a/lib/CodeGen/CGObjCGNU.cpp
> +++ b/lib/CodeGen/CGObjCGNU.cpp
> @@ -472,7 +472,7 @@ protected:
>
> /// Emits a pointer to the named class
> virtual llvm::Value *GetClassNamed(CodeGenFunction &CGF,
> - const std::string &Name, bool isWeak);
> + StringRef Name, bool isWeak, bool isDLLImport);
>
> /// Looks up the method for sending a message to the specified object. This
> /// mechanism differs between the GCC and GNU runtimes, so this method must be
> @@ -866,21 +866,24 @@ protected:
> }
>
> llvm::Value *GetClassNamed(CodeGenFunction &CGF,
> - const std::string &Name, bool isWeak) override {
> + StringRef Name, bool isWeak, bool isDLLImport) override {
> if (isWeak)
> - return CGObjCGNU::GetClassNamed(CGF, Name, isWeak);
> + return CGObjCGNU::GetClassNamed(CGF, Name, isWeak, isDLLImport);
>
> EmitClassRef(Name);
>
> - std::string SymbolName = "_OBJC_CLASS_" + Name;
> + std::string SymbolName = "_OBJC_CLASS_" + Name.str();
>
> llvm::GlobalVariable *ClassSymbol = TheModule.getGlobalVariable(SymbolName);
>
> - if (!ClassSymbol)
> + if (!ClassSymbol) {
> ClassSymbol = new llvm::GlobalVariable(TheModule, LongTy, false,
> llvm::GlobalValue::ExternalLinkage,
> nullptr, SymbolName);
> -
> + if (isDLLImport)
> + ClassSymbol->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
> + }
> +
> return ClassSymbol;
> }
>
> @@ -1054,8 +1057,8 @@ CGObjCGNU::CGObjCGNU(CodeGenModule &cgm, unsigned runtimeABIVersion,
> }
>
> llvm::Value *CGObjCGNU::GetClassNamed(CodeGenFunction &CGF,
> - const std::string &Name,
> - bool isWeak) {
> + StringRef Name,
> + bool isWeak, bool isDLLImport) {
> llvm::Constant *ClassName = MakeConstantString(Name);
> // With the incompatible ABI, this will need to be replaced with a direct
> // reference to the class symbol. For the compatible nonfragile ABI we are
> @@ -1077,11 +1080,12 @@ llvm::Value *CGObjCGNU::GetClassNamed(CodeGenFunction &CGF,
> // techniques can modify the name -> class mapping.
> llvm::Value *CGObjCGNU::GetClass(CodeGenFunction &CGF,
> const ObjCInterfaceDecl *OID) {
> - return GetClassNamed(CGF, OID->getNameAsString(), OID->isWeakImported());
> + return GetClassNamed(CGF, OID->getNameAsString(), OID->isWeakImported(),
> + OID->hasAttr<DLLImportAttr>());
getNameAsString() returns a std::string, so the change to StringRef in
GetClassNamed will add an extra conversion for no real purpose.
Perhaps that should remain const std::string & instead?
> }
>
> llvm::Value *CGObjCGNU::EmitNSAutoreleasePoolClassRef(CodeGenFunction &CGF) {
> - return GetClassNamed(CGF, "NSAutoreleasePool", false);
> + return GetClassNamed(CGF, "NSAutoreleasePool", false, CGF.CGM.getTarget().getTriple().isKnownWindowsMSVCEnvironment());
> }
>
> llvm::Value *CGObjCGNU::GetSelector(CodeGenFunction &CGF, Selector Sel,
> @@ -2878,7 +2882,10 @@ llvm::Value *CGObjCGNU::EmitIvarOffset(CodeGenFunction &CGF,
> const ObjCIvarDecl *Ivar) {
> if (CGM.getLangOpts().ObjCRuntime.isNonFragile()) {
> Interface = FindIvarInterface(CGM.getContext(), Interface, Ivar);
> - if (RuntimeVersion < 10)
> + // The MSVC linker cannot have a single global defined as LinkOnceAnyLinkage and
> + // ExternalLinkage, so create a reference to the ivar global and rely on the
> + // definition being created as part of GenerateClass.
> + if (RuntimeVersion < 10 || CGF.CGM.getTarget().getTriple().isKnownWindowsMSVCEnvironment())
> return CGF.Builder.CreateZExtOrBitCast(
> CGF.Builder.CreateDefaultAlignedLoad(CGF.Builder.CreateAlignedLoad(
> ObjCIvarOffsetVariable(Interface, Ivar),
> diff --git a/test/Sema/dllimport.c b/test/Sema/dllimport.c
> index f863499..b2e2d3c 100644
> --- a/test/Sema/dllimport.c
> +++ b/test/Sema/dllimport.c
> @@ -4,12 +4,12 @@
> // RUN: %clang_cc1 -triple x86_64-mingw32 -fsyntax-only -fms-extensions -verify -std=c99 -DGNU %s
>
> // Invalid usage.
> -__declspec(dllimport) typedef int typedef1; // expected-warning{{'dllimport' attribute only applies to variables and functions}}
> -typedef __declspec(dllimport) int typedef2; // expected-warning{{'dllimport' attribute only applies to variables and functions}}
> -typedef int __declspec(dllimport) typedef3; // expected-warning{{'dllimport' attribute only applies to variables and functions}}
> -typedef __declspec(dllimport) void (*FunTy)(); // expected-warning{{'dllimport' attribute only applies to variables and functions}}
> -enum __declspec(dllimport) Enum { EnumVal }; // expected-warning{{'dllimport' attribute only applies to variables and functions}}
> -struct __declspec(dllimport) Record {}; // expected-warning{{'dllimport' attribute only applies to variables and functions}}
> +__declspec(dllimport) typedef int typedef1; // expected-warning{{'dllimport' attribute only applies to variables, functions and classes}}
> +typedef __declspec(dllimport) int typedef2; // expected-warning{{'dllimport' attribute only applies to variables, functions and classes}}
> +typedef int __declspec(dllimport) typedef3; // expected-warning{{'dllimport' attribute only applies to variables, functions and classes}}
> +typedef __declspec(dllimport) void (*FunTy)(); // expected-warning{{'dllimport' attribute only applies to variables, functions and classes}}
> +enum __declspec(dllimport) Enum { EnumVal }; // expected-warning{{'dllimport' attribute only applies to variables, functions and classes}}
> +struct __declspec(dllimport) Record {}; // expected-warning{{'dllimport' attribute only applies to variables, functions and classes}}
>
>
>
> diff --git a/test/SemaObjC/dllimport.m b/test/SemaObjC/dllimport.m
> new file mode 100644
> index 0000000..b8fde7c
> --- /dev/null
> +++ b/test/SemaObjC/dllimport.m
> @@ -0,0 +1,19 @@
> +// RUN: %clang -fsyntax-only -fms-extensions %s -Xclang -verify
> +#if !__LP64__
> +// expected-no-diagnostics
> +#endif
> +
> + at interface NSObject @end
> +
> +#if __LP64__
> +__declspec(dllimport) // expected-warning {{__declspec attribute 'dllimport' is not supported}}
> +#else
> +__declspec(dllimport)
> +#endif
> + at interface testinterface : NSObject
> +- (void)testmethod;
> + at end
> +
> + at implementation testinterface
> +- (void)testmethod { }
> + at end
> \ No newline at end of file
Can you add a newline to the end of this file?
~Aaron
More information about the cfe-commits
mailing list