Skip to content

"vtt" missing in SubroutineType #104765

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
mgschossmann opened this issue Aug 19, 2024 · 2 comments
Open

"vtt" missing in SubroutineType #104765

mgschossmann opened this issue Aug 19, 2024 · 2 comments
Labels
clang:codegen IR generation bugs: mangling, exceptions, etc. debuginfo

Comments

@mgschossmann
Copy link
Contributor

When compiling following source, clang creates a virtual destructor for A with an artificial vtt argument. The DILocalVariable for vtt correctly has arg: 2.
However, the field types of the DISubroutineType for this virtual destructor seems to miss the additional parameter, as it only has two members and thus represents a function with only one parameter.

Source:

struct B {
    virtual ~B() {}
};

struct A : virtual B {
};

A a;

LLVM-IR:

[...]
!5 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "A", file: !3, line: 5, size: 64, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !6, vtableHolder: !8, identifier: "_ZTS1A")
[...]
!34 = !DISubroutineType(types: !35)
!35 = !{null, !36}
!36 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
[...]
!70 = distinct !DISubprogram(name: "~A", linkageName: "_ZN1AD2Ev", scope: !5, file: !3, line: 5, type: !34, scopeLine: 5, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, declaration: !44, retainedNodes: !38)
!71 = !DILocalVariable(name: "this", arg: 1, scope: !70, type: !40, flags: DIFlagArtificial | DIFlagObjectPointer)
!72 = !DILocation(line: 0, scope: !70)
!73 = !DILocalVariable(name: "vtt", arg: 2, scope: !70, type: !74, flags: DIFlagArtificial)
!74 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !75, size: 64)
!75 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
[...]

I generated the IR using clang 19.1.0-rc2 on x86_64-unknown-linux-gnu.
DWARF generated from this IR is not affected and includes all formal parameters.

The issue seems to be that in ItaniumCXXABI::addImplicitStructorParams, the parameter is added, but in CGDebugInfo::getOrCreateMethodType another type array is read to create the DISubroutineType.

void ItaniumCXXABI::addImplicitStructorParams(CodeGenFunction &CGF,
QualType &ResTy,
FunctionArgList &Params) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
assert(isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD));
// Check if we need a VTT parameter as well.
if (NeedsVTTParameter(CGF.CurGD)) {
ASTContext &Context = getContext();
// FIXME: avoid the fake decl
LangAS AS = CGM.GetGlobalVarAddressSpace(nullptr);
QualType Q = Context.getAddrSpaceQualType(Context.VoidPtrTy, AS);
QualType T = Context.getPointerType(Q);
auto *VTTDecl = ImplicitParamDecl::Create(
Context, /*DC=*/nullptr, MD->getLocation(), &Context.Idents.get("vtt"),
T, ImplicitParamKind::CXXVTT);
Params.insert(Params.begin() + 1, VTTDecl);
getStructorImplicitParamDecl(CGF) = VTTDecl;
}
}

llvm::DISubroutineType *
CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
llvm::DIFile *Unit) {
const FunctionProtoType *Func = Method->getType()->getAs<FunctionProtoType>();
if (Method->isStatic())
return cast_or_null<llvm::DISubroutineType>(
getOrCreateType(QualType(Func, 0), Unit));
return getOrCreateInstanceMethodType(Method->getThisType(), Func, Unit);
}

@EugeneZelenko EugeneZelenko added clang:codegen IR generation bugs: mangling, exceptions, etc. debuginfo and removed new issue labels Aug 19, 2024
@llvmbot
Copy link
Member

llvmbot commented Aug 19, 2024

@llvm/issue-subscribers-clang-codegen

Author: None (mgschossmann)

When compiling following source, clang creates a virtual destructor for `A` with an artificial `vtt` argument. The `DILocalVariable` for `vtt` correctly has `arg: 2`. However, the field `types` of the `DISubroutineType` for this virtual destructor seems to miss the additional parameter, as it only has two members and thus represents a function with only one parameter.

Source:

struct B {
    virtual ~B() {}
};

struct A : virtual B {
};

A a;

LLVM-IR:

[...]
!5 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "A", file: !3, line: 5, size: 64, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !6, vtableHolder: !8, identifier: "_ZTS1A")
[...]
!34 = !DISubroutineType(types: !35)
!35 = !{null, !36}
!36 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
[...]
!70 = distinct !DISubprogram(name: "~A", linkageName: "_ZN1AD2Ev", scope: !5, file: !3, line: 5, type: !34, scopeLine: 5, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, declaration: !44, retainedNodes: !38)
!71 = !DILocalVariable(name: "this", arg: 1, scope: !70, type: !40, flags: DIFlagArtificial | DIFlagObjectPointer)
!72 = !DILocation(line: 0, scope: !70)
!73 = !DILocalVariable(name: "vtt", arg: 2, scope: !70, type: !74, flags: DIFlagArtificial)
!74 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !75, size: 64)
!75 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
[...]

I generated the IR using clang 19.1.0-rc2 on x86_64-unknown-linux-gnu.
DWARF generated from this IR is not affected and includes all formal parameters.

The issue seems to be that in ItaniumCXXABI::addImplicitStructorParams, the parameter is added, but in CGDebugInfo::getOrCreateMethodType another type array is read to create the DISubroutineType.

void ItaniumCXXABI::addImplicitStructorParams(CodeGenFunction &CGF,
QualType &ResTy,
FunctionArgList &Params) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
assert(isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD));
// Check if we need a VTT parameter as well.
if (NeedsVTTParameter(CGF.CurGD)) {
ASTContext &Context = getContext();
// FIXME: avoid the fake decl
LangAS AS = CGM.GetGlobalVarAddressSpace(nullptr);
QualType Q = Context.getAddrSpaceQualType(Context.VoidPtrTy, AS);
QualType T = Context.getPointerType(Q);
auto *VTTDecl = ImplicitParamDecl::Create(
Context, /*DC=*/nullptr, MD->getLocation(), &Context.Idents.get("vtt"),
T, ImplicitParamKind::CXXVTT);
Params.insert(Params.begin() + 1, VTTDecl);
getStructorImplicitParamDecl(CGF) = VTTDecl;
}
}

llvm::DISubroutineType *
CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
llvm::DIFile *Unit) {
const FunctionProtoType *Func = Method->getType()->getAs<FunctionProtoType>();
if (Method->isStatic())
return cast_or_null<llvm::DISubroutineType>(
getOrCreateType(QualType(Func, 0), Unit));
return getOrCreateInstanceMethodType(Method->getThisType(), Func, Unit);
}

@llvmbot
Copy link
Member

llvmbot commented Aug 19, 2024

@llvm/issue-subscribers-debuginfo

Author: None (mgschossmann)

When compiling following source, clang creates a virtual destructor for `A` with an artificial `vtt` argument. The `DILocalVariable` for `vtt` correctly has `arg: 2`. However, the field `types` of the `DISubroutineType` for this virtual destructor seems to miss the additional parameter, as it only has two members and thus represents a function with only one parameter.

Source:

struct B {
    virtual ~B() {}
};

struct A : virtual B {
};

A a;

LLVM-IR:

[...]
!5 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "A", file: !3, line: 5, size: 64, flags: DIFlagTypePassByReference | DIFlagNonTrivial, elements: !6, vtableHolder: !8, identifier: "_ZTS1A")
[...]
!34 = !DISubroutineType(types: !35)
!35 = !{null, !36}
!36 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !5, size: 64, flags: DIFlagArtificial | DIFlagObjectPointer)
[...]
!70 = distinct !DISubprogram(name: "~A", linkageName: "_ZN1AD2Ev", scope: !5, file: !3, line: 5, type: !34, scopeLine: 5, flags: DIFlagArtificial | DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !2, declaration: !44, retainedNodes: !38)
!71 = !DILocalVariable(name: "this", arg: 1, scope: !70, type: !40, flags: DIFlagArtificial | DIFlagObjectPointer)
!72 = !DILocation(line: 0, scope: !70)
!73 = !DILocalVariable(name: "vtt", arg: 2, scope: !70, type: !74, flags: DIFlagArtificial)
!74 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !75, size: 64)
!75 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64)
[...]

I generated the IR using clang 19.1.0-rc2 on x86_64-unknown-linux-gnu.
DWARF generated from this IR is not affected and includes all formal parameters.

The issue seems to be that in ItaniumCXXABI::addImplicitStructorParams, the parameter is added, but in CGDebugInfo::getOrCreateMethodType another type array is read to create the DISubroutineType.

void ItaniumCXXABI::addImplicitStructorParams(CodeGenFunction &CGF,
QualType &ResTy,
FunctionArgList &Params) {
const CXXMethodDecl *MD = cast<CXXMethodDecl>(CGF.CurGD.getDecl());
assert(isa<CXXConstructorDecl>(MD) || isa<CXXDestructorDecl>(MD));
// Check if we need a VTT parameter as well.
if (NeedsVTTParameter(CGF.CurGD)) {
ASTContext &Context = getContext();
// FIXME: avoid the fake decl
LangAS AS = CGM.GetGlobalVarAddressSpace(nullptr);
QualType Q = Context.getAddrSpaceQualType(Context.VoidPtrTy, AS);
QualType T = Context.getPointerType(Q);
auto *VTTDecl = ImplicitParamDecl::Create(
Context, /*DC=*/nullptr, MD->getLocation(), &Context.Idents.get("vtt"),
T, ImplicitParamKind::CXXVTT);
Params.insert(Params.begin() + 1, VTTDecl);
getStructorImplicitParamDecl(CGF) = VTTDecl;
}
}

llvm::DISubroutineType *
CGDebugInfo::getOrCreateMethodType(const CXXMethodDecl *Method,
llvm::DIFile *Unit) {
const FunctionProtoType *Func = Method->getType()->getAs<FunctionProtoType>();
if (Method->isStatic())
return cast_or_null<llvm::DISubroutineType>(
getOrCreateType(QualType(Func, 0), Unit));
return getOrCreateInstanceMethodType(Method->getThisType(), Func, Unit);
}

rnk pushed a commit that referenced this issue Apr 16, 2025
…130674)

Fixes issue #104765: When creating a virtual destructor with an
artificial "vtt" argument, the type of "vtt" was previously missing in
the `DISubroutineType` `types` array.

This commit fixes this behavior and adds a regression test.
var-const pushed a commit to ldionne/llvm-project that referenced this issue Apr 17, 2025
…lvm#130674)

Fixes issue llvm#104765: When creating a virtual destructor with an
artificial "vtt" argument, the type of "vtt" was previously missing in
the `DISubroutineType` `types` array.

This commit fixes this behavior and adds a regression test.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
clang:codegen IR generation bugs: mangling, exceptions, etc. debuginfo
Projects
None yet
Development

No branches or pull requests

3 participants