forked from OSchip/llvm-project
[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:
parent
6c3d625fd9
commit
cac8ce06dd
|
@ -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;
|
||||||
|
|
|
@ -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; }
|
||||||
|
|
Loading…
Reference in New Issue