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 {
|
||||
struct FunctionIsDirectlyRecursive :
|
||||
public RecursiveASTVisitor<FunctionIsDirectlyRecursive> {
|
||||
|
@ -1726,6 +1736,7 @@ namespace {
|
|||
}
|
||||
};
|
||||
|
||||
// Make sure we're not referencing non-imported vars or functions.
|
||||
struct DLLImportFunctionVisitor
|
||||
: public RecursiveASTVisitor<DLLImportFunctionVisitor> {
|
||||
bool SafeToInline = true;
|
||||
|
@ -1733,12 +1744,25 @@ namespace {
|
|||
bool shouldVisitImplicitCode() const { return true; }
|
||||
|
||||
bool VisitVarDecl(VarDecl *VD) {
|
||||
// A thread-local variable cannot be imported.
|
||||
SafeToInline = !VD->getTLSKind();
|
||||
if (VD->getTLSKind()) {
|
||||
// A thread-local variable cannot be imported.
|
||||
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;
|
||||
}
|
||||
|
||||
// Make sure we're not referencing non-imported vars or functions.
|
||||
bool VisitDeclRefExpr(DeclRefExpr *E) {
|
||||
ValueDecl *VD = E->getDecl();
|
||||
if (isa<FunctionDecl>(VD))
|
||||
|
@ -1747,10 +1771,12 @@ namespace {
|
|||
SafeToInline = !V->hasGlobalStorage() || V->hasAttr<DLLImportAttr>();
|
||||
return SafeToInline;
|
||||
}
|
||||
|
||||
bool VisitCXXConstructExpr(CXXConstructExpr *E) {
|
||||
SafeToInline = E->getConstructor()->hasAttr<DLLImportAttr>();
|
||||
return SafeToInline;
|
||||
}
|
||||
|
||||
bool VisitCXXMemberCallExpr(CXXMemberCallExpr *E) {
|
||||
CXXMethodDecl *M = E->getMethodDecl();
|
||||
if (!M) {
|
||||
|
@ -1761,10 +1787,12 @@ namespace {
|
|||
}
|
||||
return SafeToInline;
|
||||
}
|
||||
|
||||
bool VisitCXXDeleteExpr(CXXDeleteExpr *E) {
|
||||
SafeToInline = E->getOperatorDelete()->hasAttr<DLLImportAttr>();
|
||||
return SafeToInline;
|
||||
}
|
||||
|
||||
bool VisitCXXNewExpr(CXXNewExpr *E) {
|
||||
SafeToInline = E->getOperatorNew()->hasAttr<DLLImportAttr>();
|
||||
return SafeToInline;
|
||||
|
@ -1793,16 +1821,6 @@ CodeGenModule::isTriviallyRecursive(const FunctionDecl *FD) {
|
|||
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) {
|
||||
if (getFunctionLinkage(GD) != llvm::Function::AvailableExternallyLinkage)
|
||||
return true;
|
||||
|
|
|
@ -368,6 +368,13 @@ struct ClassWithCtor { ClassWithCtor() {} };
|
|||
struct __declspec(dllimport) ClassWithNonDllImportFieldWithCtor { ClassWithCtor t; };
|
||||
USECLASS(ClassWithNonDllImportFieldWithCtor);
|
||||
// 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.
|
||||
__declspec(dllimport) inline void FunctionWithTLSVar() { static __thread int x = 42; }
|
||||
|
|
Loading…
Reference in New Issue