Skip to content

Commit 9939843

Browse files
committed
[lldb][DWARFASTParserClang][NFCI] Factor out CV-qualifier/is_static parsing from ParseChildParameters
This patch continues simplifying `ParseChildParameters` by moving the logic that parses the first parameter of a function DIE in case it's an implicit object parameter. Since with GCC and now Clang function declarations have `DW_AT_object_pointer`s, we should be able to check for its 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 #120856). This patch corrects this, but it should still be NFC because any parameter in C++ called "this" *is* an implicit object parameter.
1 parent 97c3a99 commit 9939843

File tree

2 files changed

+112
-65
lines changed

2 files changed

+112
-65
lines changed

lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp

Lines changed: 109 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,79 @@ static bool TagIsRecordType(dw_tag_t tag) {
159159
}
160160
}
161161

162+
/// Get the object parameter DIE if one exists, otherwise returns
163+
/// a default DWARFDIE. If \c containing_decl_ctx is not a valid
164+
/// C++ declaration context for class methods, assume no object
165+
/// parameter exists for the given \c subprogram.
166+
static DWARFDIE
167+
GetCXXObjectParameter(const DWARFDIE &subprogram,
168+
clang::DeclContext const &containing_decl_ctx) {
169+
assert(subprogram.Tag() == DW_TAG_subprogram ||
170+
subprogram.Tag() == DW_TAG_inlined_subroutine ||
171+
subprogram.Tag() == DW_TAG_subroutine_type);
172+
173+
if (!DeclKindIsCXXClass(containing_decl_ctx.getDeclKind()))
174+
return {};
175+
176+
if (!subprogram.HasChildren())
177+
return {};
178+
179+
// FIXME: if subprogram has a explicit DW_AT_object_pointer, use it.
180+
181+
// If no DW_AT_object_pointer was specified, assume the implicit object
182+
// parameter is the first parameter to the function, is called "this" and is
183+
// artificial (which is what most compilers would generate).
184+
auto children = subprogram.children();
185+
auto it = llvm::find_if(children, [](const DWARFDIE &child) {
186+
return child.Tag() == DW_TAG_formal_parameter;
187+
});
188+
189+
if (it == children.end())
190+
return {};
191+
192+
DWARFDIE object_pointer = *it;
193+
194+
if (!object_pointer.GetAttributeValueAsUnsigned(DW_AT_artificial, 0))
195+
return {};
196+
197+
// Often times compilers omit the "this" name for the
198+
// specification DIEs, so we can't rely upon the name being in
199+
// the formal parameter DIE...
200+
if (char const *name = object_pointer.GetName();
201+
name && ::strcmp(name, "this") == 0)
202+
return {};
203+
204+
return object_pointer;
205+
}
206+
207+
/// In order to determine the CV-qualifiers for a C++ class
208+
/// method in DWARF, we have to look at the CV-qualifiers of
209+
/// the object parameter's type.
210+
static unsigned GetCXXMethodCVQuals(DWARFDIE const &subprogram,
211+
DWARFDIE const &object_parameter) {
212+
if (!subprogram || !object_parameter)
213+
return 0;
214+
215+
Type *this_type = subprogram.ResolveTypeUID(
216+
object_parameter.GetAttributeValueAsReferenceDIE(DW_AT_type));
217+
if (!this_type)
218+
return 0;
219+
220+
uint32_t encoding_mask = this_type->GetEncodingMask();
221+
222+
// FIXME: explicit object parameters need not to be pointers
223+
if (!(encoding_mask & (1u << Type::eEncodingIsPointerUID)))
224+
return 0;
225+
226+
unsigned cv_quals = 0;
227+
if (encoding_mask & (1u << Type::eEncodingIsConstUID))
228+
cv_quals |= clang::Qualifiers::Const;
229+
if (encoding_mask & (1u << Type::eEncodingIsVolatileUID))
230+
cv_quals |= clang::Qualifiers::Volatile;
231+
232+
return cv_quals;
233+
}
234+
162235
TypeSP DWARFASTParserClang::ParseTypeFromClangModule(const SymbolContext &sc,
163236
const DWARFDIE &die,
164237
Log *log) {
@@ -1188,11 +1261,8 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
11881261
const dw_tag_t tag = die.Tag();
11891262

11901263
bool is_variadic = false;
1191-
bool is_static = false;
11921264
bool has_template_params = false;
11931265

1194-
unsigned type_quals = 0;
1195-
11961266
DEBUG_PRINTF("0x%8.8" PRIx64 ": %s (\"%s\")\n", die.GetID(),
11971267
DW_TAG_value_to_name(tag), type_name_cstr);
11981268

@@ -1215,23 +1285,15 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
12151285
DWARFDIE decl_ctx_die;
12161286
clang::DeclContext *containing_decl_ctx =
12171287
GetClangDeclContextContainingDIE(die, &decl_ctx_die);
1218-
const clang::Decl::Kind containing_decl_kind =
1219-
containing_decl_ctx->getDeclKind();
1220-
1221-
bool is_cxx_method = DeclKindIsCXXClass(containing_decl_kind);
1222-
// Start off static. This will be set to false in
1223-
// ParseChildParameters(...) if we find a "this" parameters as the
1224-
// first parameter
1225-
if (is_cxx_method) {
1226-
is_static = true;
1227-
}
1288+
assert(containing_decl_ctx);
12281289

12291290
if (die.HasChildren()) {
1230-
ParseChildParameters(containing_decl_ctx, die, is_static, is_variadic,
1291+
ParseChildParameters(containing_decl_ctx, die, is_variadic,
12311292
has_template_params, function_param_types,
1232-
function_param_decls, type_quals);
1293+
function_param_decls);
12331294
}
12341295

1296+
bool is_cxx_method = DeclKindIsCXXClass(containing_decl_ctx->getDeclKind());
12351297
bool ignore_containing_context = false;
12361298
// Check for templatized class member functions. If we had any
12371299
// DW_TAG_template_type_parameter or DW_TAG_template_value_parameter
@@ -1251,12 +1313,16 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
12511313
clang::CallingConv calling_convention =
12521314
ConvertDWARFCallingConventionToClang(attrs);
12531315

1316+
const DWARFDIE object_parameter =
1317+
GetCXXObjectParameter(die, *containing_decl_ctx);
1318+
12541319
// clang_type will get the function prototype clang type after this
12551320
// call
12561321
CompilerType clang_type =
12571322
m_ast.CreateFunctionType(return_clang_type, function_param_types.data(),
12581323
function_param_types.size(), is_variadic,
1259-
type_quals, calling_convention, attrs.ref_qual);
1324+
GetCXXMethodCVQuals(die, object_parameter),
1325+
calling_convention, attrs.ref_qual);
12601326

12611327
if (attrs.name) {
12621328
bool type_handled = false;
@@ -1267,6 +1333,8 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
12671333
type_handled =
12681334
ParseObjCMethod(*objc_method, die, clang_type, attrs, is_variadic);
12691335
} else if (is_cxx_method) {
1336+
// In DWARF, a C++ method is static if it has no object parameter child.
1337+
const bool is_static = !object_parameter.IsValid();
12701338
auto [handled, type_sp] =
12711339
ParseCXXMethod(die, clang_type, attrs, decl_ctx_die, is_static,
12721340
ignore_containing_context);
@@ -2315,10 +2383,8 @@ size_t DWARFASTParserClang::ParseChildEnumerators(
23152383

23162384
ConstString
23172385
DWARFASTParserClang::ConstructDemangledNameFromDWARF(const DWARFDIE &die) {
2318-
bool is_static = false;
23192386
bool is_variadic = false;
23202387
bool has_template_params = false;
2321-
unsigned type_quals = 0;
23222388
std::vector<CompilerType> param_types;
23232389
std::vector<clang::ParmVarDecl *> param_decls;
23242390
StreamString sstr;
@@ -2328,9 +2394,13 @@ DWARFASTParserClang::ConstructDemangledNameFromDWARF(const DWARFDIE &die) {
23282394

23292395
clang::DeclContext *containing_decl_ctx =
23302396
GetClangDeclContextContainingDIE(die, nullptr);
2331-
ParseChildParameters(containing_decl_ctx, die, is_static, is_variadic,
2332-
has_template_params, param_types, param_decls,
2333-
type_quals);
2397+
assert(containing_decl_ctx);
2398+
2399+
const unsigned cv_quals = GetCXXMethodCVQuals(
2400+
die, GetCXXObjectParameter(die, *containing_decl_ctx));
2401+
2402+
ParseChildParameters(containing_decl_ctx, die, is_variadic,
2403+
has_template_params, param_types, param_decls);
23342404
sstr << "(";
23352405
for (size_t i = 0; i < param_types.size(); i++) {
23362406
if (i > 0)
@@ -2340,7 +2410,7 @@ DWARFASTParserClang::ConstructDemangledNameFromDWARF(const DWARFDIE &die) {
23402410
if (is_variadic)
23412411
sstr << ", ...";
23422412
sstr << ")";
2343-
if (type_quals & clang::Qualifiers::Const)
2413+
if (cv_quals & clang::Qualifiers::Const)
23442414
sstr << " const";
23452415

23462416
return ConstString(sstr.GetString());
@@ -3070,57 +3140,37 @@ bool DWARFASTParserClang::ParseChildMembers(
30703140
return true;
30713141
}
30723142

3073-
size_t DWARFASTParserClang::ParseChildParameters(
3143+
void DWARFASTParserClang::ParseChildParameters(
30743144
clang::DeclContext *containing_decl_ctx, const DWARFDIE &parent_die,
3075-
bool &is_static, bool &is_variadic, bool &has_template_params,
3145+
bool &is_variadic, bool &has_template_params,
30763146
std::vector<CompilerType> &function_param_types,
3077-
std::vector<clang::ParmVarDecl *> &function_param_decls,
3078-
unsigned &type_quals) {
3147+
std::vector<clang::ParmVarDecl *> &function_param_decls) {
30793148
if (!parent_die)
3080-
return 0;
3149+
return;
30813150

3082-
size_t arg_idx = 0;
30833151
for (DWARFDIE die : parent_die.children()) {
30843152
const dw_tag_t tag = die.Tag();
30853153
switch (tag) {
30863154
case DW_TAG_formal_parameter: {
3155+
if (die.GetAttributeValueAsUnsigned(DW_AT_artificial, 0))
3156+
continue;
3157+
30873158
const char *name = die.GetName();
30883159
DWARFDIE param_type_die = die.GetAttributeValueAsReferenceDIE(DW_AT_type);
30893160

3090-
if (die.GetAttributeValueAsUnsigned(DW_AT_artificial, 0)) {
3091-
// In order to determine if a C++ member function is "const" we
3092-
// have to look at the const-ness of "this"...
3093-
if (arg_idx == 0 &&
3094-
DeclKindIsCXXClass(containing_decl_ctx->getDeclKind()) &&
3095-
// Often times compilers omit the "this" name for the
3096-
// specification DIEs, so we can't rely upon the name being in
3097-
// the formal parameter DIE...
3098-
(name == nullptr || ::strcmp(name, "this") == 0)) {
3099-
if (Type *this_type = die.ResolveTypeUID(param_type_die)) {
3100-
uint32_t encoding_mask = this_type->GetEncodingMask();
3101-
if (encoding_mask & Type::eEncodingIsPointerUID) {
3102-
is_static = false;
3103-
3104-
if (encoding_mask & (1u << Type::eEncodingIsConstUID))
3105-
type_quals |= clang::Qualifiers::Const;
3106-
if (encoding_mask & (1u << Type::eEncodingIsVolatileUID))
3107-
type_quals |= clang::Qualifiers::Volatile;
3108-
}
3109-
}
3110-
}
3111-
} else if (Type *type = die.ResolveTypeUID(param_type_die)) {
3112-
function_param_types.push_back(type->GetForwardCompilerType());
3161+
Type *type = die.ResolveTypeUID(param_type_die);
3162+
if (!type)
3163+
break;
31133164

3114-
clang::ParmVarDecl *param_var_decl = m_ast.CreateParameterDeclaration(
3115-
containing_decl_ctx, GetOwningClangModule(die), name,
3116-
type->GetForwardCompilerType(), clang::StorageClass::SC_None);
3117-
assert(param_var_decl);
3118-
function_param_decls.push_back(param_var_decl);
3165+
function_param_types.push_back(type->GetForwardCompilerType());
31193166

3120-
m_ast.SetMetadataAsUserID(param_var_decl, die.GetID());
3121-
}
3167+
clang::ParmVarDecl *param_var_decl = m_ast.CreateParameterDeclaration(
3168+
containing_decl_ctx, GetOwningClangModule(die), name,
3169+
type->GetForwardCompilerType(), clang::StorageClass::SC_None);
3170+
assert(param_var_decl);
3171+
function_param_decls.push_back(param_var_decl);
31223172

3123-
arg_idx++;
3173+
m_ast.SetMetadataAsUserID(param_var_decl, die.GetID());
31243174
} break;
31253175

31263176
case DW_TAG_unspecified_parameters:
@@ -3142,7 +3192,6 @@ size_t DWARFASTParserClang::ParseChildParameters(
31423192
break;
31433193
}
31443194
}
3145-
return arg_idx;
31463195
}
31473196

31483197
clang::Decl *DWARFASTParserClang::GetClangDeclForDIE(const DWARFDIE &die) {

lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -186,14 +186,12 @@ class DWARFASTParserClang : public lldb_private::plugin::dwarf::DWARFASTParser {
186186
const lldb::AccessType default_accessibility,
187187
lldb_private::ClangASTImporter::LayoutInfo &layout_info);
188188

189-
size_t
189+
void
190190
ParseChildParameters(clang::DeclContext *containing_decl_ctx,
191191
const lldb_private::plugin::dwarf::DWARFDIE &parent_die,
192-
bool &is_static, bool &is_variadic,
193-
bool &has_template_params,
192+
bool &is_variadic, bool &has_template_params,
194193
std::vector<lldb_private::CompilerType> &function_args,
195-
std::vector<clang::ParmVarDecl *> &function_param_decls,
196-
unsigned &type_quals);
194+
std::vector<clang::ParmVarDecl *> &function_param_decls);
197195

198196
size_t ParseChildEnumerators(
199197
const lldb_private::CompilerType &compiler_type, bool is_signed,

0 commit comments

Comments
 (0)