diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp --- a/clang/lib/AST/Type.cpp +++ b/clang/lib/AST/Type.cpp @@ -4287,9 +4287,14 @@ const RecordDecl *RD = RT->getDecl(); if (const auto *CXXRD = dyn_cast(RD)) { /// Check if this is a C++ object with a non-trivial destructor. - if (CXXRD->hasDefinition() && !CXXRD->hasTrivialDestructor()) + /// If the type is only forward-declared, assume it might need destruction. + if (!CXXRD->hasDefinition() || !CXXRD->hasTrivialDestructor()) return DK_cxx_destructor; } else { + // FIXME: should this also return true for forward declared types? It + // seems a bit weird, as C doesn't support destructors...but objc-arc now + // does. + /// Check if this is a C struct that is non-trivial to destroy or an array /// that contains such a struct. if (RD->isNonTrivialToPrimitiveDestroy()) diff --git a/clang/test/CodeGenCXX/cxx2a-thread-local-constinit.cpp b/clang/test/CodeGenCXX/cxx2a-thread-local-constinit.cpp --- a/clang/test/CodeGenCXX/cxx2a-thread-local-constinit.cpp +++ b/clang/test/CodeGenCXX/cxx2a-thread-local-constinit.cpp @@ -12,8 +12,9 @@ // LINUX-DAG: @d = thread_local global i32 0, align 4 // DARWIN-DAG: @d = internal thread_local global i32 0, align 4 // CHECK-DAG: @e = external thread_local global %struct.Destructed, align 4 -// CHECK-DAG: @e2 = thread_local global %struct.Destructed zeroinitializer, align 4 -// CHECK-DAG: @f = thread_local global i32 4, align 4 +// CHECK-DAG: @f = external thread_local global %struct.MaybeDestructed, align 1 +// CHECK-DAG: @g = thread_local global %struct.Destructed zeroinitializer, align 4 +// CHECK-DAG: @h = thread_local global i32 4, align 4 extern thread_local int a; extern thread_local constinit int b; @@ -74,13 +75,20 @@ // CHECK: } int get_e() { return e.n; } -// CHECK: define {{.*}}[[E2_INIT:@__cxx_global_var_init[^(]*]]( -// LINUX: call {{.*}} @__cxa_thread_atexit({{.*}} @_ZN10DestructedD1Ev {{.*}} @e2 -// DARWIN: call {{.*}} @_tlv_atexit({{.*}} @_ZN10DestructedD1Ev {{.*}} @e2 -thread_local constinit Destructed e2; +struct MaybeDestructed; // forward-declared, can't tell if it has a destructor. +extern thread_local constinit MaybeDestructed f; +// CHECK-LABEL: define %struct.MaybeDestructed* @_Z5get_fv() +// CHECK: call {{.*}}* @_ZTW1f() +// CHECK: } +MaybeDestructed* get_f() { return &f; } + +// CHECK: define {{.*}}[[G_INIT:@__cxx_global_var_init[^(]*]]( +// LINUX: call {{.*}} @__cxa_thread_atexit({{.*}} @_ZN10DestructedD1Ev {{.*}} @g +// DARWIN: call {{.*}} @_tlv_atexit({{.*}} @_ZN10DestructedD1Ev {{.*}} @g +thread_local constinit Destructed g; -thread_local constinit int f = 4; +thread_local constinit int h = 4; // CHECK-LABEL: define {{.*}}__tls_init // CHECK: call {{.*}} [[D_INIT]] -// CHECK: call {{.*}} [[E2_INIT]] +// CHECK: call {{.*}} [[G_INIT]]