// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir // RUN: FileCheck --input-file=%t.cir %s // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll // RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s // RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll // RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s template struct Base { virtual ~Base() {} virtual void foo() {} T val; }; extern template class Base; void use(Base *p) { p->foo(); } // Constructing a Base forces the vtable to be emitted. Base make_base() { Base b; return b; } // Class with a key function (out-of-line virtual destructor). template struct KeyBase { virtual ~KeyBase(); T val; }; template KeyBase::~KeyBase() {} extern template class KeyBase; void use_key() { KeyBase k; (void)k; } // Base has no key function and extern template declaration, so the vtable // gets external linkage. // CHECK: cir.global "private" external @_ZTV4BaseIiE // The key function (~KeyBase) is not instantiated in this TU, so the vtable // also gets external linkage. // CHECK: cir.global "private" external @_ZTV7KeyBaseIiE // Verify the virtual call goes through the vtable. // CHECK: cir.func {{.*}} @_Z3useP4BaseIiE // CHECK: cir.vtable.get_vptr // CHECK: cir.vtable.get_virtual_fn_addr // LLVM: @_ZTV4BaseIiE = external global // LLVM: @_ZTV7KeyBaseIiE = external global // LLVM: define {{.*}} @_Z3useP4BaseIiE // OGCG: @_ZTV4BaseIiE = external constant // OGCG: @_ZTV7KeyBaseIiE = external constant // OGCG: define {{.*}} @_Z3useP4BaseIiE