From 6eaa8323a887a878f54dfcc65d4fff72c0f5c161 Mon Sep 17 00:00:00 2001 From: Hans Wennborg Date: Fri, 28 Aug 2015 21:47:01 +0000 Subject: Allow TLS vars in dllimport/export functions; only inline dllimport functions when safe (PR24593) This patch does two things: 1) Don't error about dllimport/export on thread-local static local variables. We put those attributes on static locals in dllimport/export functions implicitly in case the function gets inlined. Now, for TLS variables this is a problem because we can't import such variables, but it's a benign problem becase: 2) Make sure we never inline a dllimport function TLS static locals. In fact, never inline a dllimport function that references a non-imported function or variable (because these are not defined in the importing library). This seems to match MSVC's behaviour. Differential Revision: http://reviews.llvm.org/D12422 llvm-svn: 246338 --- clang/lib/CodeGen/CodeGenModule.cpp | 38 +++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) (limited to 'clang/lib/CodeGen/CodeGenModule.cpp') diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 0525869..847cb57 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -1448,6 +1448,35 @@ namespace { return true; } }; + + struct DLLImportFunctionVisitor + : public RecursiveASTVisitor { + bool SafeToInline = true; + + bool VisitVarDecl(VarDecl *VD) { + // A thread-local variable cannot be imported. + SafeToInline = !VD->getTLSKind(); + return SafeToInline; + } + + // Make sure we're not referencing non-imported vars or functions. + bool VisitDeclRefExpr(DeclRefExpr *E) { + ValueDecl *VD = E->getDecl(); + if (isa(VD)) + SafeToInline = VD->hasAttr(); + else if (VarDecl *V = dyn_cast(VD)) + SafeToInline = !V->hasGlobalStorage() || V->hasAttr(); + return SafeToInline; + } + bool VisitCXXDeleteExpr(CXXDeleteExpr *E) { + SafeToInline = E->getOperatorDelete()->hasAttr(); + return SafeToInline; + } + bool VisitCXXNewExpr(CXXNewExpr *E) { + SafeToInline = E->getOperatorNew()->hasAttr(); + return SafeToInline; + } + }; } // isTriviallyRecursive - Check if this function calls another @@ -1478,6 +1507,15 @@ CodeGenModule::shouldEmitFunction(GlobalDecl GD) { const auto *F = cast(GD.getDecl()); if (CodeGenOpts.OptimizationLevel == 0 && !F->hasAttr()) return false; + + if (F->hasAttr()) { + // Check whether it would be safe to inline this dllimport function. + DLLImportFunctionVisitor Visitor; + Visitor.TraverseFunctionDecl(const_cast(F)); + if (!Visitor.SafeToInline) + return false; + } + // PR9614. Avoid cases where the source code is lying to us. An available // externally function should have an equivalent function somewhere else, // but a function that calls itself is clearly not equivalent to the real -- cgit v1.1