Index: clang/lib/CodeGen/CodeGenModule.cpp =================================================================== --- clang/lib/CodeGen/CodeGenModule.cpp +++ clang/lib/CodeGen/CodeGenModule.cpp @@ -32,7 +32,6 @@ #include "clang/AST/DeclTemplate.h" #include "clang/AST/Mangle.h" #include "clang/AST/RecordLayout.h" -#include "clang/AST/RecursiveASTVisitor.h" #include "clang/AST/StmtVisitor.h" #include "clang/Basic/Builtins.h" #include "clang/Basic/CharInfo.h" @@ -2317,64 +2316,95 @@ // Make sure we're not referencing non-imported vars or functions. struct DLLImportFunctionVisitor - : public RecursiveASTVisitor { - bool SafeToInline = true; - - bool shouldVisitImplicitCode() const { return true; } - - bool VisitVarDecl(VarDecl *VD) { - if (VD->getTLSKind()) { - // A thread-local variable cannot be imported. - SafeToInline = false; - return SafeToInline; + : public ConstStmtVisitor { + bool VisitDeclStmt(const DeclStmt *E) { + for (const Decl *D : E->decls()) { + if (const auto *VD = dyn_cast(D)) { + if (!VisitVarDecl(VD)) + return false; + // Traverse variable initializers, which are common sources of + // function references. + if (!VisitStmt(VD->getInit())) + return false; + } } + return true; + } + + bool VisitVarDecl(const VarDecl *VD) { + // A thread-local variable cannot be imported. + if (VD->getTLSKind()) + return false; // A variable definition might imply a destructor call. if (VD->isThisDeclarationADefinition()) - SafeToInline = !HasNonDllImportDtor(VD->getType()); + if (HasNonDllImportDtor(VD->getType())) + return false; - return SafeToInline; + return true; } - bool VisitCXXBindTemporaryExpr(CXXBindTemporaryExpr *E) { + bool VisitCXXBindTemporaryExpr(const CXXBindTemporaryExpr *E) { + bool SafeToInline = true; if (const auto *D = E->getTemporary()->getDestructor()) SafeToInline = D->hasAttr(); return SafeToInline; } - bool VisitDeclRefExpr(DeclRefExpr *E) { - ValueDecl *VD = E->getDecl(); + bool VisitDeclRefExpr(const DeclRefExpr *E) { + const ValueDecl *VD = E->getDecl(); + bool SafeToInline = true; if (isa(VD)) SafeToInline = VD->hasAttr(); - else if (VarDecl *V = dyn_cast(VD)) + else if (const VarDecl *V = dyn_cast(VD)) SafeToInline = !V->hasGlobalStorage() || V->hasAttr(); return SafeToInline; } - bool VisitCXXConstructExpr(CXXConstructExpr *E) { - SafeToInline = E->getConstructor()->hasAttr(); - return SafeToInline; + bool VisitCXXConstructExpr(const CXXConstructExpr *E) { + return E->getConstructor()->hasAttr(); } - bool VisitCXXMemberCallExpr(CXXMemberCallExpr *E) { - CXXMethodDecl *M = E->getMethodDecl(); - if (!M) { - // Call through a pointer to member function. This is safe to inline. - SafeToInline = true; - } else { + bool VisitCXXMemberCallExpr(const CXXMemberCallExpr *E) { + // If M is null, this is a call through a pointer to member function. This + // is safe to inline. + const CXXMethodDecl *M = E->getMethodDecl(); + bool SafeToInline = true; + if (M) SafeToInline = M->hasAttr(); - } return SafeToInline; } - bool VisitCXXDeleteExpr(CXXDeleteExpr *E) { - SafeToInline = E->getOperatorDelete()->hasAttr(); - return SafeToInline; + bool VisitCXXDeleteExpr(const CXXDeleteExpr *E) { + return E->getOperatorDelete()->hasAttr(); } - bool VisitCXXNewExpr(CXXNewExpr *E) { - SafeToInline = E->getOperatorNew()->hasAttr(); - return SafeToInline; + bool VisitCXXNewExpr(const CXXNewExpr *E) { + return E->getOperatorNew()->hasAttr(); + } + + bool VisitStmt(const Stmt *S) { + if (!S) + return true; + for (const Stmt *Child : S->children()) + if (Child && !this->Visit(Child)) + return false; + return true; + } + + static bool isSafeToInline(const FunctionDecl *FD) { + DLLImportFunctionVisitor Visitor; + if (!Visitor.Visit(FD->getBody())) + return false; + + // We also need to check constructor initializers. + if (const auto *Ctor = dyn_cast(FD)) { + for (auto *I : Ctor->inits()) { + if (!Visitor.Visit(I->getInit())) + return false; + } + } + return true; } }; } @@ -2409,9 +2439,7 @@ if (F->hasAttr()) { // Check whether it would be safe to inline this dllimport function. - DLLImportFunctionVisitor Visitor; - Visitor.TraverseFunctionDecl(const_cast(F)); - if (!Visitor.SafeToInline) + if (!DLLImportFunctionVisitor::isSafeToInline(F)) return false; if (const CXXDestructorDecl *Dtor = dyn_cast(F)) {