[dllimport] Check for dtor references in functions

Destructor references are not modelled explicitly in the AST. This adds
checks for destructor calls due to variable definitions and temporaries.

If a dllimport function references a non-dllimport destructor, it must
not be emitted available_externally, as the referenced destructor might
live across the DLL boundary and isn't exported.

llvm-svn: 295258
This commit is contained in:
Hans Wennborg 2017-02-15 23:28:10 +00:00
parent 6c3d625fd9
commit cac8ce06dd
2 changed files with 38 additions and 13 deletions

View File

@ -1693,6 +1693,16 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) {
} }
} }
// Check if T is a class type with a destructor that's not dllimport.
static bool HasNonDllImportDtor(QualType T) {
if (const auto *RT = T->getBaseElementTypeUnsafe()->getAs<RecordType>())
if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
if (RD->getDestructor() && !RD->getDestructor()->hasAttr<DLLImportAttr>())
return true;
return false;
}
namespace { namespace {
struct FunctionIsDirectlyRecursive : struct FunctionIsDirectlyRecursive :
public RecursiveASTVisitor<FunctionIsDirectlyRecursive> { public RecursiveASTVisitor<FunctionIsDirectlyRecursive> {
@ -1726,6 +1736,7 @@ namespace {
} }
}; };
// Make sure we're not referencing non-imported vars or functions.
struct DLLImportFunctionVisitor struct DLLImportFunctionVisitor
: public RecursiveASTVisitor<DLLImportFunctionVisitor> { : public RecursiveASTVisitor<DLLImportFunctionVisitor> {
bool SafeToInline = true; bool SafeToInline = true;
@ -1733,12 +1744,25 @@ namespace {
bool shouldVisitImplicitCode() const { return true; } bool shouldVisitImplicitCode() const { return true; }
bool VisitVarDecl(VarDecl *VD) { bool VisitVarDecl(VarDecl *VD) {
if (VD->getTLSKind()) {
// A thread-local variable cannot be imported. // A thread-local variable cannot be imported.
SafeToInline = !VD->getTLSKind(); SafeToInline = false;
return SafeToInline;
}
// A variable definition might imply a destructor call.
if (VD->isThisDeclarationADefinition())
SafeToInline = !HasNonDllImportDtor(VD->getType());
return SafeToInline;
}
bool VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) {
if (const auto *D = E->getTemporary()->getDestructor())
SafeToInline = D->hasAttr<DLLImportAttr>();
return SafeToInline; return SafeToInline;
} }
// Make sure we're not referencing non-imported vars or functions.
bool VisitDeclRefExpr(DeclRefExpr *E) { bool VisitDeclRefExpr(DeclRefExpr *E) {
ValueDecl *VD = E->getDecl(); ValueDecl *VD = E->getDecl();
if (isa<FunctionDecl>(VD)) if (isa<FunctionDecl>(VD))
@ -1747,10 +1771,12 @@ namespace {
SafeToInline = !V->hasGlobalStorage() || V->hasAttr<DLLImportAttr>(); SafeToInline = !V->hasGlobalStorage() || V->hasAttr<DLLImportAttr>();
return SafeToInline; return SafeToInline;
} }
bool VisitCXXConstructExpr(CXXConstructExpr *E) { bool VisitCXXConstructExpr(CXXConstructExpr *E) {
SafeToInline = E->getConstructor()->hasAttr<DLLImportAttr>(); SafeToInline = E->getConstructor()->hasAttr<DLLImportAttr>();
return SafeToInline; return SafeToInline;
} }
bool VisitCXXMemberCallExpr(CXXMemberCallExpr *E) { bool VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
CXXMethodDecl *M = E->getMethodDecl(); CXXMethodDecl *M = E->getMethodDecl();
if (!M) { if (!M) {
@ -1761,10 +1787,12 @@ namespace {
} }
return SafeToInline; return SafeToInline;
} }
bool VisitCXXDeleteExpr(CXXDeleteExpr *E) { bool VisitCXXDeleteExpr(CXXDeleteExpr *E) {
SafeToInline = E->getOperatorDelete()->hasAttr<DLLImportAttr>(); SafeToInline = E->getOperatorDelete()->hasAttr<DLLImportAttr>();
return SafeToInline; return SafeToInline;
} }
bool VisitCXXNewExpr(CXXNewExpr *E) { bool VisitCXXNewExpr(CXXNewExpr *E) {
SafeToInline = E->getOperatorNew()->hasAttr<DLLImportAttr>(); SafeToInline = E->getOperatorNew()->hasAttr<DLLImportAttr>();
return SafeToInline; return SafeToInline;
@ -1793,16 +1821,6 @@ CodeGenModule::isTriviallyRecursive(const FunctionDecl *FD) {
return Walker.Result; return Walker.Result;
} }
// Check if T is a class type with a destructor that's not dllimport.
static bool HasNonDllImportDtor(QualType T) {
if (const auto *RT = T->getBaseElementTypeUnsafe()->getAs<RecordType>())
if (CXXRecordDecl *RD = dyn_cast<CXXRecordDecl>(RT->getDecl()))
if (RD->getDestructor() && !RD->getDestructor()->hasAttr<DLLImportAttr>())
return true;
return false;
}
bool CodeGenModule::shouldEmitFunction(GlobalDecl GD) { bool CodeGenModule::shouldEmitFunction(GlobalDecl GD) {
if (getFunctionLinkage(GD) != llvm::Function::AvailableExternallyLinkage) if (getFunctionLinkage(GD) != llvm::Function::AvailableExternallyLinkage)
return true; return true;

View File

@ -368,6 +368,13 @@ struct ClassWithCtor { ClassWithCtor() {} };
struct __declspec(dllimport) ClassWithNonDllImportFieldWithCtor { ClassWithCtor t; }; struct __declspec(dllimport) ClassWithNonDllImportFieldWithCtor { ClassWithCtor t; };
USECLASS(ClassWithNonDllImportFieldWithCtor); USECLASS(ClassWithNonDllImportFieldWithCtor);
// MO1-DAG: declare dllimport x86_thiscallcc %struct.ClassWithNonDllImportFieldWithCtor* @"\01??0ClassWithNonDllImportFieldWithCtor@@QAE@XZ"(%struct.ClassWithNonDllImportFieldWithCtor* returned) // MO1-DAG: declare dllimport x86_thiscallcc %struct.ClassWithNonDllImportFieldWithCtor* @"\01??0ClassWithNonDllImportFieldWithCtor@@QAE@XZ"(%struct.ClassWithNonDllImportFieldWithCtor* returned)
struct ClassWithImplicitDtor { __declspec(dllimport) ClassWithImplicitDtor(); ClassWithDtor member; };
__declspec(dllimport) inline void ReferencingDtorThroughDefinition() { ClassWithImplicitDtor x; };
USE(ReferencingDtorThroughDefinition)
// MO1-DAG: declare dllimport void @"\01?ReferencingDtorThroughDefinition@@YAXXZ"()
__declspec(dllimport) inline void ReferencingDtorThroughTemporary() { ClassWithImplicitDtor(); };
USE(ReferencingDtorThroughTemporary)
// MO1-DAG: declare dllimport void @"\01?ReferencingDtorThroughTemporary@@YAXXZ"()
// A dllimport function with a TLS variable must not be available_externally. // A dllimport function with a TLS variable must not be available_externally.
__declspec(dllimport) inline void FunctionWithTLSVar() { static __thread int x = 42; } __declspec(dllimport) inline void FunctionWithTLSVar() { static __thread int x = 42; }