Try harder to not inline dllimport functions referencing non-dllimport functions
authorHans Wennborg <hans@hanshq.net>
Tue, 13 Sep 2016 21:08:20 +0000 (21:08 +0000)
committerHans Wennborg <hans@hanshq.net>
Tue, 13 Sep 2016 21:08:20 +0000 (21:08 +0000)
In r246338, code was added to check for this, but it failed to take into
account implicit destructor invocations because those are not reflected
in the AST. This adds a separate check for them.

llvm-svn: 281395

clang/lib/CodeGen/CodeGenModule.cpp
clang/test/CodeGenCXX/dllimport-members.cpp
clang/test/CodeGenCXX/dllimport.cpp

index 1b6f5c3..085482b 100644 (file)
@@ -1740,8 +1740,17 @@ CodeGenModule::isTriviallyRecursive(const FunctionDecl *FD) {
   return Walker.Result;
 }
 
-bool
-CodeGenModule::shouldEmitFunction(GlobalDecl GD) {
+// Check if T is a class type with a destructor that's not dllimport.
+static bool HasNonDllImportDtor(QualType T) {
+  if (const RecordType *RT = dyn_cast<RecordType>(T))
+    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;
   const auto *F = cast<FunctionDecl>(GD.getDecl());
@@ -1754,6 +1763,18 @@ CodeGenModule::shouldEmitFunction(GlobalDecl GD) {
     Visitor.TraverseFunctionDecl(const_cast<FunctionDecl*>(F));
     if (!Visitor.SafeToInline)
       return false;
+
+    if (const CXXDestructorDecl *Dtor = dyn_cast<CXXDestructorDecl>(F)) {
+      // Implicit destructor invocations aren't captured in the AST, so the
+      // check above can't see them. Check for them manually here.
+      for (const Decl *Member : Dtor->getParent()->decls())
+        if (isa<FieldDecl>(Member))
+          if (HasNonDllImportDtor(cast<FieldDecl>(Member)->getType()))
+            return false;
+      for (const CXXBaseSpecifier &B : Dtor->getParent()->bases())
+        if (HasNonDllImportDtor(B.getType()))
+          return false;
+    }
   }
 
   // PR9614. Avoid cases where the source code is lying to us. An available
index 1fed1bf..19d9e1d 100644 (file)
@@ -44,7 +44,7 @@ void useSpecials() {
 }
 
 // Used to force non-trivial special members.
-struct ForceNonTrivial {
+struct __declspec(dllimport) ForceNonTrivial {
   ForceNonTrivial();
   ~ForceNonTrivial();
   ForceNonTrivial(const ForceNonTrivial&);
index aff240f..1a24e34 100644 (file)
@@ -347,6 +347,13 @@ __declspec(dllimport) inline int *ReferencingImportedDelete() { delete (int*)nul
 // MO1-DAG: define available_externally dllimport i32* @"\01?ReferencingImportedDelete@@YAPAHXZ"
 USE(ReferencingImportedNew)
 USE(ReferencingImportedDelete)
+struct ClassWithDtor { ~ClassWithDtor() {} };
+struct __declspec(dllimport) ClassWithNonDllImportField { ClassWithDtor t; };
+struct __declspec(dllimport) ClassWithNonDllImportBase : public ClassWithDtor { };
+USECLASS(ClassWithNonDllImportField);
+USECLASS(ClassWithNonDllImportBase);
+// MO1-DAG: declare dllimport x86_thiscallcc void @"\01??1ClassWithNonDllImportBase@@QAE@XZ"(%struct.ClassWithNonDllImportBase*)
+// MO1-DAG: declare dllimport x86_thiscallcc void @"\01??1ClassWithNonDllImportField@@QAE@XZ"(%struct.ClassWithNonDllImportField*)
 
 // A dllimport function with a TLS variable must not be available_externally.
 __declspec(dllimport) inline void FunctionWithTLSVar() { static __thread int x = 42; }