Author: Erich Keane Date: 2026-04-03T05:59:46-07:00 New Revision: 0a3fdd30e58e9467205aca6133a13b7077a9ce68
URL: https://github.com/llvm/llvm-project/commit/0a3fdd30e58e9467205aca6133a13b7077a9ce68 DIFF: https://github.com/llvm/llvm-project/commit/0a3fdd30e58e9467205aca6133a13b7077a9ce68.diff LOG: [CIR] Handle vtable-lowering-with-incomplete types (#190216) The NYI diagnostic in getFunctionTypeForVTable showed up a few times in testing, so this patch is attempting to fix that up. The reproducer here is a function type for a vtable that has an incomplete type in it(return or parameter). Classic codegen chooses to represent this as an opaque type. This patch instead removes the special v-table handling here, so that we can instead just represent the types as incomplete record types. At the moment, this patch ends up lowering incomplete types as 'empty' types in LLVM-IR, which we may find we need to modify in the future, however at the moment, it seems to work. This patch ALSO changes the definition of RecordType::isSized to only be true for complete types, which prevents a number of other things from attempting to add attributes/check the size of the type/etc, but those are irrelevant for the purposes of vtable emission. Added: clang/test/CIR/CodeGen/vtable-nyi-nonconvertible-functype.cpp Modified: clang/include/clang/CIR/Dialect/IR/CIRTypes.td clang/lib/CIR/CodeGen/CIRGenCall.cpp clang/lib/CIR/CodeGen/CIRGenTypes.h clang/lib/CIR/CodeGen/CIRGenVTables.cpp Removed: ################################################################################ diff --git a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td index 1ff55a2b21ee1..f3ee572251bbf 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRTypes.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRTypes.td @@ -762,6 +762,10 @@ def CIR_RecordType : CIR_Type<"Record", "record", [ // a conflict in RecordStorage because two types will have the same hash. void removeABIConversionNamePrefix(); + bool isSized() const { + return isComplete(); + } + private: static constexpr char abi_conversion_prefix[] = "__post_abi_"; diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp index 35479fa8097ce..876fef687b477 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -65,16 +65,6 @@ cir::FuncType CIRGenTypes::getFunctionType(const CIRGenFunctionInfo &info) { info.isVariadic()); } -cir::FuncType CIRGenTypes::getFunctionTypeForVTable(GlobalDecl gd) { - const CXXMethodDecl *md = cast<CXXMethodDecl>(gd.getDecl()); - const FunctionProtoType *fpt = md->getType()->getAs<FunctionProtoType>(); - - if (!isFuncTypeConvertible(fpt)) - cgm.errorNYI("getFunctionTypeForVTable: non-convertible function type"); - - return getFunctionType(gd); -} - CIRGenCallee CIRGenCallee::prepareConcreteCallee(CIRGenFunction &cgf) const { if (isVirtual()) { const CallExpr *ce = getVirtualCallExpr(); diff --git a/clang/lib/CIR/CodeGen/CIRGenTypes.h b/clang/lib/CIR/CodeGen/CIRGenTypes.h index 749a18b62544e..172b348ac78cf 100644 --- a/clang/lib/CIR/CodeGen/CIRGenTypes.h +++ b/clang/lib/CIR/CodeGen/CIRGenTypes.h @@ -132,11 +132,6 @@ class CIRGenTypes { cir::FuncType getFunctionType(clang::GlobalDecl gd); - /// Get the CIR function type for use in a vtable, given a CXXMethodDecl. If - /// the method has an incomplete return type, and/or incomplete argument - /// types, this will return the opaque type. - cir::FuncType getFunctionTypeForVTable(clang::GlobalDecl gd); - // The arrangement methods are split into three families: // - those meant to drive the signature and prologue/epilogue // of a function declaration or definition, diff --git a/clang/lib/CIR/CodeGen/CIRGenVTables.cpp b/clang/lib/CIR/CodeGen/CIRGenVTables.cpp index ceaceb2ffb66a..56839ca03dbb1 100644 --- a/clang/lib/CIR/CodeGen/CIRGenVTables.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenVTables.cpp @@ -212,7 +212,7 @@ mlir::Attribute CIRGenVTables::getVTableComponent( assert(!cir::MissingFeatures::pointerAuthentication()); } else { // Otherwise we can use the method definition directly. - cir::FuncType fnTy = cgm.getTypes().getFunctionTypeForVTable(gd); + cir::FuncType fnTy = cgm.getTypes().getFunctionType(gd); fnPtr = cgm.getAddrOfFunction(gd, fnTy, /*ForVTable=*/true); } @@ -827,7 +827,7 @@ cir::FuncOp CIRGenVTables::maybeEmitThunk(GlobalDecl gd, mCtx.mangleThunk(md, thunkAdjustments, /*elideOverrideInfo=*/true, out); } - cir::FuncType thunkVTableTy = cgm.getTypes().getFunctionTypeForVTable(gd); + cir::FuncType thunkVTableTy = cgm.getTypes().getFunctionType(gd); cir::FuncOp thunk = cgm.getAddrOfThunk(name, thunkVTableTy, gd); // If we don't need to emit a definition, return this declaration as is. diff --git a/clang/test/CIR/CodeGen/vtable-nyi-nonconvertible-functype.cpp b/clang/test/CIR/CodeGen/vtable-nyi-nonconvertible-functype.cpp new file mode 100644 index 0000000000000..f7c5a96420de1 --- /dev/null +++ b/clang/test/CIR/CodeGen/vtable-nyi-nonconvertible-functype.cpp @@ -0,0 +1,66 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM,LLVMCIR --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=LLVM,OGCG --input-file=%t.ll %s + +// CIR-DAG: !rec_Param2 = !cir.record<struct "Param2" incomplete> +// CIR-DAG: !rec_Ret1 = !cir.record<struct "Ret1" incomplete> +// CIR-DAG: !rec_S1 = !cir.record<struct "S1" {!cir.vptr}> +// CIR-DAG: !rec_S2 = !cir.record<struct "S2" {!cir.vptr}> +// LLVMCIR-DAG: %struct.Ret1 = type {} +// LLVMCIR-DAG: %struct.Param2 = type {} + +struct Ret1; + +struct S1 { + virtual void key(); + virtual Ret1 badReturn(); +}; + +void S1::key() {} + +// CIR: @_ZTV2S1 = #cir.vtable<{ +// CIR-SAME: #cir.const_array<[ +// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>, +// CIR-SAME: #cir.global_view<@_ZTI2S1> : !cir.ptr<!u8i>, +// CIR-SAME: #cir.global_view<@_ZN2S13keyEv> : !cir.ptr<!u8i>, +// CIR-SAME: #cir.global_view<@_ZN2S19badReturnEv> : !cir.ptr<!u8i>]> : +// CIR-SAME: !cir.array<!cir.ptr<!u8i> x 4>}> + +// LLVM: @_ZTV2S1 = {{.*}}{ [4 x ptr] } { [4 x ptr] [ +// LLVM-SAME: ptr null, +// LLVM-SAME: ptr @_ZTI2S1, +// LLVM-SAME: ptr @_ZN2S13keyEv, +// LLVM-SAME: ptr @_ZN2S19badReturnEv] } + +struct Param2; + +struct S2 { + virtual void key(); + virtual void badParam(Param2 x); +}; + +void S2::key() {} +// CIR: @_ZTV2S2 = #cir.vtable<{ +// CIR-SAME: #cir.const_array<[ +// CIR-SAME: #cir.ptr<null> : !cir.ptr<!u8i>, +// CIR-SAME: #cir.global_view<@_ZTI2S2> : !cir.ptr<!u8i>, +// CIR-SAME: #cir.global_view<@_ZN2S23keyEv> : !cir.ptr<!u8i>, +// CIR-SAME: #cir.global_view<@_ZN2S28badParamE6Param2> : !cir.ptr<!u8i>]> : +// CIR-SAME: !cir.array<!cir.ptr<!u8i> x 4>}> + +// LLVM: @_ZTV2S2 = {{.*}}{ [4 x ptr] } { [4 x ptr] [ +// LLVM-SAME: ptr null, +// LLVM-SAME: ptr @_ZTI2S2, +// LLVM-SAME: ptr @_ZN2S23keyEv, +// LLVM-SAME: ptr @_ZN2S28badParamE6Param2] } + + +// CIR: cir.func private @_ZN2S19badReturnEv(!cir.ptr<!rec_S1> {llvm.align = 8 : i64, llvm.dereferenceable = 8 : i64, llvm.nonnull, llvm.noundef}) -> !rec_Ret1 +// LLVMCIR: declare %struct.Ret1 @_ZN2S19badReturnEv(ptr noundef nonnull align 8 dereferenceable(8)) +// OGCG: declare void @_ZN2S19badReturnEv() +// CIR: cir.func private @_ZN2S28badParamE6Param2(!cir.ptr<!rec_S2> {llvm.align = 8 : i64, llvm.dereferenceable = 8 : i64, llvm.nonnull, llvm.noundef}, !rec_Param2) +// LLVMCIR: declare void @_ZN2S28badParamE6Param2(ptr noundef nonnull align 8 dereferenceable(8), %struct.Param2) +// OGCG: declare void @_ZN2S28badParamE6Param2() unnamed_addr _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
