[lldb][DWARFASTParserClang][NFCI] Factor out CV-qualifier/is_static parsing from ParseChildParameters (#123951)

This patch continues simplifying `ParseChildParameters` by moving out
the logic that parses the first parameter of a function DIE into a
helper function. Since with GCC (and lately Clang) function declarations
have `DW_AT_object_pointer`s, we should be able to check for the
attribute's existence to determine if a function is static (and also
deduce CV-qualifiers from it). This will be useful for cases where the
object parameter is explicit (which is possible since C++23).

This should be NFC. I added a FIXME to places where we assume an
implicit object parameter (which will be addressed in a follow-up
patch).

We used to guard parsing of the CV-qualifiers of the "this" parameter
with a `encoding_mask & Type::eEncodingIsPointerUID`, which is
incorrect, because `eEncodingIsPointerUID` cannot be used as a bitmask
directly (see https://github.com/llvm/llvm-project/issues/120856). This
patch corrects this, but it should still be NFC because any parameter in
C++ called "this" *is* an implicit object parameter.
This commit is contained in:
Michael Buch 2025-01-22 17:47:26 +00:00 committed by GitHub
parent f78359cf43
commit 511dc261ab
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 109 additions and 65 deletions

View File

@ -159,6 +159,76 @@ static bool TagIsRecordType(dw_tag_t tag) {
}
}
/// Get the object parameter DIE if one exists, otherwise returns
/// a default DWARFDIE. If \c containing_decl_ctx is not a valid
/// C++ declaration context for class methods, assume no object
/// parameter exists for the given \c subprogram.
static DWARFDIE
GetCXXObjectParameter(const DWARFDIE &subprogram,
const clang::DeclContext &containing_decl_ctx) {
assert(subprogram.Tag() == DW_TAG_subprogram ||
subprogram.Tag() == DW_TAG_inlined_subroutine ||
subprogram.Tag() == DW_TAG_subroutine_type);
if (!DeclKindIsCXXClass(containing_decl_ctx.getDeclKind()))
return {};
// FIXME: if subprogram has a explicit DW_AT_object_pointer, use it.
// If no DW_AT_object_pointer was specified, assume the implicit object
// parameter is the first parameter to the function, is called "this" and is
// artificial (which is what most compilers would generate).
auto children = subprogram.children();
auto it = llvm::find_if(children, [](const DWARFDIE &child) {
return child.Tag() == DW_TAG_formal_parameter;
});
if (it == children.end())
return {};
DWARFDIE object_pointer = *it;
if (!object_pointer.GetAttributeValueAsUnsigned(DW_AT_artificial, 0))
return {};
// Often times compilers omit the "this" name for the
// specification DIEs, so we can't rely upon the name being in
// the formal parameter DIE...
if (const char *name = object_pointer.GetName();
name && ::strcmp(name, "this") != 0)
return {};
return object_pointer;
}
/// In order to determine the CV-qualifiers for a C++ class
/// method in DWARF, we have to look at the CV-qualifiers of
/// the object parameter's type.
static unsigned GetCXXMethodCVQuals(const DWARFDIE &subprogram,
const DWARFDIE &object_parameter) {
if (!subprogram || !object_parameter)
return 0;
Type *this_type = subprogram.ResolveTypeUID(
object_parameter.GetAttributeValueAsReferenceDIE(DW_AT_type));
if (!this_type)
return 0;
uint32_t encoding_mask = this_type->GetEncodingMask();
// FIXME: explicit object parameters need not to be pointers
if (!(encoding_mask & (1u << Type::eEncodingIsPointerUID)))
return 0;
unsigned cv_quals = 0;
if (encoding_mask & (1u << Type::eEncodingIsConstUID))
cv_quals |= clang::Qualifiers::Const;
if (encoding_mask & (1u << Type::eEncodingIsVolatileUID))
cv_quals |= clang::Qualifiers::Volatile;
return cv_quals;
}
TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc,
const DWARFDIE &die,
Log *log) {
@ -1188,11 +1258,8 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
const dw_tag_t tag = die.Tag();
bool is_variadic = false;
bool is_static = false;
bool has_template_params = false;
unsigned type_quals = 0;
DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(),
DW_TAG_value_to_name(tag), type_name_cstr);
@ -1215,23 +1282,15 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
DWARFDIE decl_ctx_die;
clang::DeclContext *containing_decl_ctx =
GetClangDeclContextContainingDIE(die, &decl_ctx_die);
const clang::Decl::Kind containing_decl_kind =
containing_decl_ctx->getDeclKind();
bool is_cxx_method = DeclKindIsCXXClass(containing_decl_kind);
// Start off static. This will be set to false in
// ParseChildParameters(...) if we find a "this" parameters as the
// first parameter
if (is_cxx_method) {
is_static = true;
}
assert(containing_decl_ctx);
if (die.HasChildren()) {
ParseChildParameters(containing_decl_ctx, die, is_static, is_variadic,
ParseChildParameters(containing_decl_ctx, die, is_variadic,
has_template_params, function_param_types,
function_param_decls, type_quals);
function_param_decls);
}
bool is_cxx_method = DeclKindIsCXXClass(containing_decl_ctx->getDeclKind());
bool ignore_containing_context = false;
// Check for templatized class member functions. If we had any
// DW_TAG_template_type_parameter or DW_TAG_template_value_parameter
@ -1251,12 +1310,16 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
clang::CallingConv calling_convention =
ConvertDWARFCallingConventionToClang(attrs);
const DWARFDIE object_parameter =
GetCXXObjectParameter(die, *containing_decl_ctx);
// clang_type will get the function prototype clang type after this
// call
CompilerType clang_type =
m_ast.CreateFunctionType(return_clang_type, function_param_types.data(),
function_param_types.size(), is_variadic,
type_quals, calling_convention, attrs.ref_qual);
GetCXXMethodCVQuals(die, object_parameter),
calling_convention, attrs.ref_qual);
if (attrs.name) {
bool type_handled = false;
@ -1267,6 +1330,8 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
type_handled =
ParseObjCMethod(*objc_method, die, clang_type, attrs, is_variadic);
} else if (is_cxx_method) {
// In DWARF, a C++ method is static if it has no object parameter child.
const bool is_static = !object_parameter.IsValid();
auto [handled, type_sp] =
ParseCXXMethod(die, clang_type, attrs, decl_ctx_die, is_static,
ignore_containing_context);
@ -2315,10 +2380,8 @@ size_t DWARFASTParserClang::ParseChildEnumerators(
ConstString
DWARFASTParserClang::ConstructDemangledNameFromDWARF(const DWARFDIE &die) {
bool is_static = false;
bool is_variadic = false;
bool has_template_params = false;
unsigned type_quals = 0;
std::vector<CompilerType> param_types;
std::vector<clang::ParmVarDecl *> param_decls;
StreamString sstr;
@ -2328,9 +2391,13 @@ DWARFASTParserClang::ConstructDemangledNameFromDWARF(const DWARFDIE &die) {
clang::DeclContext *containing_decl_ctx =
GetClangDeclContextContainingDIE(die, nullptr);
ParseChildParameters(containing_decl_ctx, die, is_static, is_variadic,
has_template_params, param_types, param_decls,
type_quals);
assert(containing_decl_ctx);
const unsigned cv_quals = GetCXXMethodCVQuals(
die, GetCXXObjectParameter(die, *containing_decl_ctx));
ParseChildParameters(containing_decl_ctx, die, is_variadic,
has_template_params, param_types, param_decls);
sstr << "(";
for (size_t i = 0; i < param_types.size(); i++) {
if (i > 0)
@ -2340,7 +2407,7 @@ DWARFASTParserClang::ConstructDemangledNameFromDWARF(const DWARFDIE &die) {
if (is_variadic)
sstr << ", ...";
sstr << ")";
if (type_quals & clang::Qualifiers::Const)
if (cv_quals & clang::Qualifiers::Const)
sstr << " const";
return ConstString(sstr.GetString());
@ -3070,57 +3137,37 @@ bool DWARFASTParserClang::ParseChildMembers(
return true;
}
size_t DWARFASTParserClang::ParseChildParameters(
void DWARFASTParserClang::ParseChildParameters(
clang::DeclContext *containing_decl_ctx, const DWARFDIE &parent_die,
bool &is_static, bool &is_variadic, bool &has_template_params,
bool &is_variadic, bool &has_template_params,
std::vector<CompilerType> &function_param_types,
std::vector<clang::ParmVarDecl *> &function_param_decls,
unsigned &type_quals) {
std::vector<clang::ParmVarDecl *> &function_param_decls) {
if (!parent_die)
return 0;
return;
size_t arg_idx = 0;
for (DWARFDIE die : parent_die.children()) {
const dw_tag_t tag = die.Tag();
switch (tag) {
case DW_TAG_formal_parameter: {
if (die.GetAttributeValueAsUnsigned(DW_AT_artificial, 0))
continue;
const char *name = die.GetName();
DWARFDIE param_type_die = die.GetAttributeValueAsReferenceDIE(DW_AT_type);
if (die.GetAttributeValueAsUnsigned(DW_AT_artificial, 0)) {
// In order to determine if a C++ member function is "const" we
// have to look at the const-ness of "this"...
if (arg_idx == 0 &&
DeclKindIsCXXClass(containing_decl_ctx->getDeclKind()) &&
// Often times compilers omit the "this" name for the
// specification DIEs, so we can't rely upon the name being in
// the formal parameter DIE...
(name == nullptr || ::strcmp(name, "this") == 0)) {
if (Type *this_type = die.ResolveTypeUID(param_type_die)) {
uint32_t encoding_mask = this_type->GetEncodingMask();
if (encoding_mask & Type::eEncodingIsPointerUID) {
is_static = false;
Type *type = die.ResolveTypeUID(param_type_die);
if (!type)
break;
if (encoding_mask & (1u << Type::eEncodingIsConstUID))
type_quals |= clang::Qualifiers::Const;
if (encoding_mask & (1u << Type::eEncodingIsVolatileUID))
type_quals |= clang::Qualifiers::Volatile;
}
}
}
} else if (Type *type = die.ResolveTypeUID(param_type_die)) {
function_param_types.push_back(type->GetForwardCompilerType());
function_param_types.push_back(type->GetForwardCompilerType());
clang::ParmVarDecl *param_var_decl = m_ast.CreateParameterDeclaration(
containing_decl_ctx, GetOwningClangModule(die), name,
type->GetForwardCompilerType(), clang::StorageClass::SC_None);
assert(param_var_decl);
function_param_decls.push_back(param_var_decl);
clang::ParmVarDecl *param_var_decl = m_ast.CreateParameterDeclaration(
containing_decl_ctx, GetOwningClangModule(die), name,
type->GetForwardCompilerType(), clang::StorageClass::SC_None);
assert(param_var_decl);
function_param_decls.push_back(param_var_decl);
m_ast.SetMetadataAsUserID(param_var_decl, die.GetID());
}
arg_idx++;
m_ast.SetMetadataAsUserID(param_var_decl, die.GetID());
} break;
case DW_TAG_unspecified_parameters:
@ -3142,7 +3189,6 @@ size_t DWARFASTParserClang::ParseChildParameters(
break;
}
}
return arg_idx;
}
clang::Decl *DWARFASTParserClang::GetClangDeclForDIE(const DWARFDIE &die) {

View File

@ -186,14 +186,12 @@ protected:
const lldb::AccessType default_accessibility,
lldb_private::ClangASTImporter::LayoutInfo &layout_info);
size_t
void
ParseChildParameters(clang::DeclContext *containing_decl_ctx,
const lldb_private::plugin::dwarf::DWARFDIE &parent_die,
bool &is_static, bool &is_variadic,
bool &has_template_params,
bool &is_variadic, bool &has_template_params,
std::vector<lldb_private::CompilerType> &function_args,
std::vector<clang::ParmVarDecl *> &function_param_decls,
unsigned &type_quals);
std::vector<clang::ParmVarDecl *> &function_param_decls);
size_t ParseChildEnumerators(
const lldb_private::CompilerType &compiler_type, bool is_signed,