Skip to content

Commit 081723b

Browse files
authored
[lldb][TypeSystem] Ensure that ParmVarDecls have the correct DeclContext (#124279)
While sifting through this part of the code I noticed that when we parse C++ methods, `DWARFASTParserClang` creates two sets of `ParmVarDecls`, one in `ParseChildParameters` and once in `AddMethodToCXXRecordType`. The former is unused when we're dealing with methods. Moreover, the `ParmVarDecls` we created in `ParseChildParameters` were created with an incorrect `clang::DeclContext` (namely the DeclContext of the function, and not the function itself). In Clang, there's `ParmVarDecl::setOwningFunction` to adjust the DeclContext of a parameter if the parameter was created before the FunctionDecl. But we never used it. This patch removes the `ParmVarDecl` creation from `ParseChildParameters` and instead creates a `TypeSystemClang::CreateParameterDeclarations` that ensures we set the DeclContext correctly. Note there is one differences in how `ParmVarDecl`s would be created now: we won't set a ClangASTMetadata entry for any of the parameters. I don't think this was ever actually useful for parameter DIEs anyway. This wasn't causing any concrete issues (that I know of), but was quite surprising. And this way of setting the parameters seems easier to reason about (in my opinion).
1 parent 561132e commit 081723b

File tree

8 files changed

+285
-52
lines changed

8 files changed

+285
-52
lines changed

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

Lines changed: 16 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1272,7 +1272,7 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
12721272
return_clang_type = m_ast.GetBasicType(eBasicTypeVoid);
12731273

12741274
std::vector<CompilerType> function_param_types;
1275-
std::vector<clang::ParmVarDecl *> function_param_decls;
1275+
llvm::SmallVector<llvm::StringRef> function_param_names;
12761276

12771277
// Parse the function children for the parameters
12781278

@@ -1284,7 +1284,7 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
12841284
if (die.HasChildren()) {
12851285
ParseChildParameters(containing_decl_ctx, die, is_variadic,
12861286
has_template_params, function_param_types,
1287-
function_param_decls);
1287+
function_param_names);
12881288
}
12891289

12901290
bool is_cxx_method = DeclKindIsCXXClass(containing_decl_ctx->getDeclKind());
@@ -1414,12 +1414,14 @@ DWARFASTParserClang::ParseSubroutine(const DWARFDIE &die,
14141414

14151415
LinkDeclContextToDIE(function_decl, die);
14161416

1417-
if (!function_param_decls.empty()) {
1418-
m_ast.SetFunctionParameters(function_decl, function_param_decls);
1419-
if (template_function_decl)
1420-
m_ast.SetFunctionParameters(template_function_decl,
1421-
function_param_decls);
1422-
}
1417+
const clang::FunctionProtoType *function_prototype(
1418+
llvm::cast<clang::FunctionProtoType>(
1419+
ClangUtil::GetQualType(clang_type).getTypePtr()));
1420+
const auto params = m_ast.CreateParameterDeclarations(
1421+
function_decl, *function_prototype, function_param_names);
1422+
function_decl->setParams(params);
1423+
if (template_function_decl)
1424+
template_function_decl->setParams(params);
14231425

14241426
ClangASTMetadata metadata;
14251427
metadata.SetUserID(die.GetID());
@@ -2380,7 +2382,7 @@ DWARFASTParserClang::ConstructDemangledNameFromDWARF(const DWARFDIE &die) {
23802382
bool is_variadic = false;
23812383
bool has_template_params = false;
23822384
std::vector<CompilerType> param_types;
2383-
std::vector<clang::ParmVarDecl *> param_decls;
2385+
llvm::SmallVector<llvm::StringRef> param_names;
23842386
StreamString sstr;
23852387

23862388
DWARFDeclContext decl_ctx = die.GetDWARFDeclContext();
@@ -2394,7 +2396,7 @@ DWARFASTParserClang::ConstructDemangledNameFromDWARF(const DWARFDIE &die) {
23942396
die, GetCXXObjectParameter(die, *containing_decl_ctx));
23952397

23962398
ParseChildParameters(containing_decl_ctx, die, is_variadic,
2397-
has_template_params, param_types, param_decls);
2399+
has_template_params, param_types, param_names);
23982400
sstr << "(";
23992401
for (size_t i = 0; i < param_types.size(); i++) {
24002402
if (i > 0)
@@ -3157,7 +3159,7 @@ void DWARFASTParserClang::ParseChildParameters(
31573159
clang::DeclContext *containing_decl_ctx, const DWARFDIE &parent_die,
31583160
bool &is_variadic, bool &has_template_params,
31593161
std::vector<CompilerType> &function_param_types,
3160-
std::vector<clang::ParmVarDecl *> &function_param_decls) {
3162+
llvm::SmallVectorImpl<llvm::StringRef> &function_param_names) {
31613163
if (!parent_die)
31623164
return;
31633165

@@ -3168,22 +3170,14 @@ void DWARFASTParserClang::ParseChildParameters(
31683170
if (die.GetAttributeValueAsUnsigned(DW_AT_artificial, 0))
31693171
continue;
31703172

3171-
const char *name = die.GetName();
31723173
DWARFDIE param_type_die = die.GetAttributeValueAsReferenceDIE(DW_AT_type);
31733174

31743175
Type *type = die.ResolveTypeUID(param_type_die);
31753176
if (!type)
31763177
break;
31773178

3179+
function_param_names.emplace_back(die.GetName());
31783180
function_param_types.push_back(type->GetForwardCompilerType());
3179-
3180-
clang::ParmVarDecl *param_var_decl = m_ast.CreateParameterDeclaration(
3181-
containing_decl_ctx, GetOwningClangModule(die), name,
3182-
type->GetForwardCompilerType(), clang::StorageClass::SC_None);
3183-
assert(param_var_decl);
3184-
function_param_decls.push_back(param_var_decl);
3185-
3186-
m_ast.SetMetadataAsUserID(param_var_decl, die.GetID());
31873181
} break;
31883182

31893183
case DW_TAG_unspecified_parameters:
@@ -3205,6 +3199,8 @@ void DWARFASTParserClang::ParseChildParameters(
32053199
break;
32063200
}
32073201
}
3202+
3203+
assert(function_param_names.size() == function_param_names.size());
32083204
}
32093205

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

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

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -186,12 +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-
void
190-
ParseChildParameters(clang::DeclContext *containing_decl_ctx,
191-
const lldb_private::plugin::dwarf::DWARFDIE &parent_die,
192-
bool &is_variadic, bool &has_template_params,
193-
std::vector<lldb_private::CompilerType> &function_args,
194-
std::vector<clang::ParmVarDecl *> &function_param_decls);
189+
void ParseChildParameters(
190+
clang::DeclContext *containing_decl_ctx,
191+
const lldb_private::plugin::dwarf::DWARFDIE &parent_die,
192+
bool &is_variadic, bool &has_template_params,
193+
std::vector<lldb_private::CompilerType> &function_param_types,
194+
llvm::SmallVectorImpl<llvm::StringRef> &function_param_names);
195195

196196
size_t ParseChildEnumerators(
197197
const lldb_private::CompilerType &compiler_type, bool is_signed,

lldb/source/Plugins/SymbolFile/NativePDB/PdbAstBuilder.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1137,7 +1137,7 @@ void PdbAstBuilder::CreateFunctionParameters(PdbCompilandSymId func_id,
11371137
}
11381138

11391139
if (!params.empty() && params.size() == param_count)
1140-
m_clang.SetFunctionParameters(&function_decl, params);
1140+
function_decl.setParams(params);
11411141
}
11421142

11431143
clang::QualType PdbAstBuilder::CreateEnumType(PdbTypeSymId id,

lldb/source/Plugins/SymbolFile/PDB/PDBASTParser.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -975,8 +975,8 @@ PDBASTParser::GetDeclForSymbol(const llvm::pdb::PDBSymbol &symbol) {
975975
}
976976
}
977977
}
978-
if (params.size())
979-
m_ast.SetFunctionParameters(decl, params);
978+
if (params.size() && decl)
979+
decl->setParams(params);
980980

981981
m_uid_to_decl[sym_id] = decl;
982982

lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2217,12 +2217,6 @@ ParmVarDecl *TypeSystemClang::CreateParameterDeclaration(
22172217
return decl;
22182218
}
22192219

2220-
void TypeSystemClang::SetFunctionParameters(
2221-
FunctionDecl *function_decl, llvm::ArrayRef<ParmVarDecl *> params) {
2222-
if (function_decl)
2223-
function_decl->setParams(params);
2224-
}
2225-
22262220
CompilerType
22272221
TypeSystemClang::CreateBlockPointerType(const CompilerType &function_type) {
22282222
QualType block_type = m_ast_up->getBlockPointerType(
@@ -7708,6 +7702,32 @@ void TypeSystemClang::SetFloatingInitializerForVariable(
77087702
ast, init_value, true, qt.getUnqualifiedType(), SourceLocation()));
77097703
}
77107704

7705+
llvm::SmallVector<clang::ParmVarDecl *>
7706+
TypeSystemClang::CreateParameterDeclarations(
7707+
clang::FunctionDecl *func, const clang::FunctionProtoType &prototype,
7708+
const llvm::SmallVector<llvm::StringRef> &parameter_names) {
7709+
assert(func);
7710+
assert(parameter_names.empty() ||
7711+
parameter_names.size() == prototype.getNumParams());
7712+
7713+
llvm::SmallVector<clang::ParmVarDecl *, 12> params;
7714+
for (unsigned param_index = 0; param_index < prototype.getNumParams();
7715+
++param_index) {
7716+
llvm::StringRef name =
7717+
!parameter_names.empty() ? parameter_names[param_index] : "";
7718+
7719+
auto *param =
7720+
CreateParameterDeclaration(func, /*owning_module=*/{}, name.data(),
7721+
GetType(prototype.getParamType(param_index)),
7722+
clang::SC_None, /*add_decl=*/false);
7723+
assert(param);
7724+
7725+
params.push_back(param);
7726+
}
7727+
7728+
return params;
7729+
}
7730+
77117731
clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
77127732
lldb::opaque_compiler_type_t type, llvm::StringRef name,
77137733
const char *mangled_name, const CompilerType &method_clang_type,
@@ -7848,20 +7868,10 @@ clang::CXXMethodDecl *TypeSystemClang::AddMethodToCXXRecordType(
78487868
getASTContext(), mangled_name, /*literal=*/false));
78497869
}
78507870

7851-
// Populate the method decl with parameter decls
7852-
7853-
llvm::SmallVector<clang::ParmVarDecl *, 12> params;
7854-
7855-
for (unsigned param_index = 0; param_index < num_params; ++param_index) {
7856-
params.push_back(clang::ParmVarDecl::Create(
7857-
getASTContext(), cxx_method_decl, clang::SourceLocation(),
7858-
clang::SourceLocation(),
7859-
nullptr, // anonymous
7860-
method_function_prototype->getParamType(param_index), nullptr,
7861-
clang::SC_None, nullptr));
7862-
}
7863-
7864-
cxx_method_decl->setParams(llvm::ArrayRef<clang::ParmVarDecl *>(params));
7871+
// Parameters on member function declarations in DWARF generally don't
7872+
// have names, so we omit them when creating the ParmVarDecls.
7873+
cxx_method_decl->setParams(CreateParameterDeclarations(
7874+
cxx_method_decl, *method_function_prototype, /*parameter_names=*/{}));
78657875

78667876
AddAccessSpecifierDecl(cxx_record_decl, getASTContext(),
78677877
GetCXXRecordDeclAccess(cxx_record_decl),

lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -489,9 +489,6 @@ class TypeSystemClang : public TypeSystem {
489489
const char *name, const CompilerType &param_type,
490490
int storage, bool add_decl = false);
491491

492-
void SetFunctionParameters(clang::FunctionDecl *function_decl,
493-
llvm::ArrayRef<clang::ParmVarDecl *> params);
494-
495492
CompilerType CreateBlockPointerType(const CompilerType &function_type);
496493

497494
// Array Types
@@ -976,6 +973,24 @@ class TypeSystemClang : public TypeSystem {
976973
SetFloatingInitializerForVariable(clang::VarDecl *var,
977974
const llvm::APFloat &init_value);
978975

976+
/// For each parameter type of \c prototype, creates a \c clang::ParmVarDecl
977+
/// whose \c clang::DeclContext is \c context.
978+
///
979+
/// \param[in] context Non-null \c clang::FunctionDecl which will be the \c
980+
/// clang::DeclContext of each parameter created/returned by this function.
981+
/// \param[in] prototype The \c clang::FunctionProtoType of \c context.
982+
/// \param[in] param_names The ith element of this vector contains the name
983+
/// of the ith parameter. This parameter may be unnamed, in which case the
984+
/// ith entry in \c param_names is an empty string. This vector is either
985+
/// empty, or will have an entry for *each* parameter of the prototype
986+
/// regardless of whether a parameter is unnamed or not.
987+
///
988+
/// \returns A list of newly created of non-null \c clang::ParmVarDecl (one
989+
/// for each parameter of \c prototype).
990+
llvm::SmallVector<clang::ParmVarDecl *> CreateParameterDeclarations(
991+
clang::FunctionDecl *context, const clang::FunctionProtoType &prototype,
992+
const llvm::SmallVector<llvm::StringRef> &param_names);
993+
979994
clang::CXXMethodDecl *AddMethodToCXXRecordType(
980995
lldb::opaque_compiler_type_t type, llvm::StringRef name,
981996
const char *mangled_name, const CompilerType &method_type,

lldb/unittests/Symbol/TestTypeSystemClang.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1040,3 +1040,45 @@ TEST_F(TestTypeSystemClang, GetDeclContextByNameWhenMissingSymbolFile) {
10401040

10411041
EXPECT_TRUE(decls.empty());
10421042
}
1043+
1044+
TEST_F(TestTypeSystemClang, AddMethodToCXXRecordType_ParmVarDecls) {
1045+
// Tests that AddMethodToCXXRecordType creates ParmVarDecl's with
1046+
// a correct clang::DeclContext.
1047+
1048+
llvm::StringRef class_name = "S";
1049+
CompilerType t = clang_utils::createRecord(*m_ast, class_name);
1050+
m_ast->StartTagDeclarationDefinition(t);
1051+
1052+
CompilerType return_type = m_ast->GetBasicType(lldb::eBasicTypeVoid);
1053+
const bool is_virtual = false;
1054+
const bool is_static = false;
1055+
const bool is_inline = false;
1056+
const bool is_explicit = true;
1057+
const bool is_attr_used = false;
1058+
const bool is_artificial = false;
1059+
1060+
llvm::SmallVector<CompilerType> param_types{
1061+
m_ast->GetBasicType(lldb::eBasicTypeInt),
1062+
m_ast->GetBasicType(lldb::eBasicTypeShort)};
1063+
CompilerType function_type = m_ast->CreateFunctionType(
1064+
return_type, param_types.data(), /*num_params*/ param_types.size(),
1065+
/*variadic=*/false, /*quals*/ 0U);
1066+
m_ast->AddMethodToCXXRecordType(
1067+
t.GetOpaqueQualType(), "myFunc", nullptr, function_type,
1068+
lldb::AccessType::eAccessPublic, is_virtual, is_static, is_inline,
1069+
is_explicit, is_attr_used, is_artificial);
1070+
1071+
// Complete the definition and check the created record.
1072+
m_ast->CompleteTagDeclarationDefinition(t);
1073+
1074+
auto *record = llvm::cast<CXXRecordDecl>(ClangUtil::GetAsTagDecl(t));
1075+
1076+
auto method_it = record->method_begin();
1077+
ASSERT_NE(method_it, record->method_end());
1078+
1079+
EXPECT_EQ(method_it->getNumParams(), param_types.size());
1080+
1081+
// DeclContext of each parameter should be the CXXMethodDecl itself.
1082+
EXPECT_EQ(method_it->getParamDecl(0)->getDeclContext(), *method_it);
1083+
EXPECT_EQ(method_it->getParamDecl(1)->getDeclContext(), *method_it);
1084+
}

0 commit comments

Comments
 (0)