Эх сурвалжийг харах

Look through array types when deciding whether a field requires non-trivial
destruction in the destructor-aliases logic. Fixes PR 9197.



git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@125447 91177308-0d34-0410-b5e6-96231b3b80d8

John McCall 14 жил өмнө
parent
commit
0d70d71ccb

+ 14 - 0
include/clang/AST/Type.h

@@ -692,6 +692,19 @@ public:
     return getObjCGCAttr() == Qualifiers::Strong;
   }
 
+  enum DestructionKind {
+    DK_none,
+    DK_cxx_destructor
+  };
+
+  /// isDestructedType - nonzero if objects of this type require
+  /// non-trivial work to clean up after.  Non-zero because it's
+  /// conceivable that qualifiers (objc_gc(weak)?) could make
+  /// something require destruction.
+  DestructionKind isDestructedType() const {
+    return isDestructedTypeImpl(*this);
+  }
+
 private:
   // These methods are implemented in a separate translation unit;
   // "static"-ize them to avoid creating temporary QualTypes in the
@@ -701,6 +714,7 @@ private:
   static SplitQualType getSplitDesugaredType(QualType T);
   static SplitQualType getSplitUnqualifiedTypeImpl(QualType type);
   static QualType IgnoreParens(QualType T);
+  static DestructionKind isDestructedTypeImpl(QualType type);
 };
 
 } // end clang.

+ 11 - 0
lib/AST/Type.cpp

@@ -1576,3 +1576,14 @@ bool Type::hasSizedVLAType() const {
 
   return false;
 }
+
+QualType::DestructionKind QualType::isDestructedTypeImpl(QualType type) {
+  /// Currently, the only destruction kind we recognize is C++ objects
+  /// with non-trivial destructors.
+  const CXXRecordDecl *record =
+    type->getBaseElementTypeUnsafe()->getAsCXXRecordDecl();
+  if (record && !record->hasTrivialDestructor())
+    return DK_cxx_destructor;
+
+  return DK_none;
+}

+ 4 - 5
lib/CodeGen/CGCXX.cpp

@@ -60,13 +60,12 @@ bool CodeGenModule::TryEmitBaseDestructorAsAlias(const CXXDestructorDecl *D) {
     return true;
   }
 
-  // If any fields have a non-trivial destructor, we have to emit it
-  // separately.
+  // If any field has a non-trivial destructor, we have to emit the
+  // destructor separately.
   for (CXXRecordDecl::field_iterator I = Class->field_begin(),
          E = Class->field_end(); I != E; ++I)
-    if (const RecordType *RT = (*I)->getType()->getAs<RecordType>())
-      if (!cast<CXXRecordDecl>(RT->getDecl())->hasTrivialDestructor())
-        return true;
+    if ((*I)->getType().isDestructedType())
+      return true;
 
   // Try to find a unique base class with a non-trivial destructor.
   const CXXRecordDecl *UniqueBase = 0;

+ 20 - 0
test/CodeGenCXX/destructors.cpp

@@ -306,6 +306,26 @@ namespace test6 {
   // CHECK:   invoke void @_ZN5test61BILj0EED2Ev
 }
 
+// PR 9197
+namespace test7 {
+  struct D { ~D(); };
+
+  struct A { ~A(); };
+  A::~A() { }
+
+  struct B : public A {
+    ~B();
+    D arr[1];
+  };
+
+  // Verify that this doesn't get emitted as an alias
+  // CHECK: define void @_ZN5test71BD2Ev(
+  // CHECK:   invoke void @_ZN5test71DD1Ev(
+  // CHECK:   call void @_ZN5test71AD2Ev(
+  B::~B() {}
+
+}
+
 // Checks from test3:
 
   // CHECK: define internal void @_ZN5test312_GLOBAL__N_11DD0Ev(%"struct.test3::<anonymous namespace>::D"* %this) unnamed_addr