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
This commit is contained in:
Hans Wennborg
2015-08-28 21:47:01 +00:00
parent e235d45026
commit 6eaa8323a8
5 changed files with 111 additions and 4 deletions

View File

@@ -1448,6 +1448,35 @@ namespace {
return true;
}
};
struct DLLImportFunctionVisitor
: public RecursiveASTVisitor<DLLImportFunctionVisitor> {
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<FunctionDecl>(VD))
SafeToInline = VD->hasAttr<DLLImportAttr>();
else if (VarDecl *V = dyn_cast<VarDecl>(VD))
SafeToInline = !V->hasGlobalStorage() || V->hasAttr<DLLImportAttr>();
return SafeToInline;
}
bool VisitCXXDeleteExpr(CXXDeleteExpr *E) {
SafeToInline = E->getOperatorDelete()->hasAttr<DLLImportAttr>();
return SafeToInline;
}
bool VisitCXXNewExpr(CXXNewExpr *E) {
SafeToInline = E->getOperatorNew()->hasAttr<DLLImportAttr>();
return SafeToInline;
}
};
}
// isTriviallyRecursive - Check if this function calls another
@@ -1478,6 +1507,15 @@ CodeGenModule::shouldEmitFunction(GlobalDecl GD) {
const auto *F = cast<FunctionDecl>(GD.getDecl());
if (CodeGenOpts.OptimizationLevel == 0 && !F->hasAttr<AlwaysInlineAttr>())
return false;
if (F->hasAttr<DLLImportAttr>()) {
// Check whether it would be safe to inline this dllimport function.
DLLImportFunctionVisitor Visitor;
Visitor.TraverseFunctionDecl(const_cast<FunctionDecl*>(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