Fix crash in indirect template instantiation. (#7240)

Provide a source location to the member expression used when a thunk
calls a member function. This ends up being used as the point of
instantiation when the return type triggers a template instantiation;
the absence of this location previously caused assertion failures within
clang.

Assisted-by: Gemini via Antigravity
This commit is contained in:
Richard Smith
2026-05-20 23:18:15 +00:00
committed by GitHub
parent f31c553e65
commit 1231098c14
2 changed files with 34 additions and 12 deletions
+16 -12
View File
@@ -16,6 +16,7 @@
#include "toolchain/check/convert.h"
#include "toolchain/check/cpp/context.h"
#include "toolchain/check/cpp/import.h"
#include "toolchain/check/cpp/location.h"
#include "toolchain/check/literal.h"
#include "toolchain/check/type.h"
#include "toolchain/check/type_completion.h"
@@ -344,10 +345,9 @@ static auto BuildThunkParameterTypes(clang::ASTContext& ast_context,
// Returns the thunk parameters using the callee function parameter identifiers.
static auto BuildThunkParameters(clang::ASTContext& ast_context,
CalleeFunctionInfo callee_info,
clang::SourceLocation clang_loc,
clang::FunctionDecl* thunk_function_decl)
-> llvm::SmallVector<clang::ParmVarDecl*> {
clang::SourceLocation clang_loc = callee_info.decl->getLocation();
const auto* thunk_function_proto_type =
thunk_function_decl->getType()->castAs<clang::FunctionProtoType>();
@@ -431,9 +431,9 @@ static auto GetDeclNameForThunk(clang::ASTContext& ast_context,
// thunk parameter types.
static auto CreateThunkFunctionDecl(
Context& context, CalleeFunctionInfo callee_info,
clang::SourceLocation clang_loc,
llvm::ArrayRef<clang::QualType> thunk_param_types) -> clang::FunctionDecl* {
clang::ASTContext& ast_context = context.ast_context();
clang::SourceLocation clang_loc = callee_info.decl->getLocation();
clang::DeclarationName name =
GetDeclNameForThunk(ast_context, callee_info.decl->getDeclName());
@@ -450,8 +450,8 @@ static auto CreateThunkFunctionDecl(
/*UsesFPIntrin=*/false, /*isInlineSpecified=*/true);
decl_context->addDecl(thunk_function_decl);
thunk_function_decl->setParams(
BuildThunkParameters(ast_context, callee_info, thunk_function_decl));
thunk_function_decl->setParams(BuildThunkParameters(
ast_context, callee_info, clang_loc, thunk_function_decl));
// Force the thunk to be inlined and discarded.
thunk_function_decl->addAttr(
@@ -541,14 +541,13 @@ static auto BuildCalleeArgs(clang::Sema& sema,
// args and returns the callee function return value. Returns nullptr on
// failure.
static auto BuildThunkBody(CppContext& cpp_context, clang::Sema& sema,
clang::SourceLocation clang_loc,
clang::FunctionDecl* thunk_function_decl,
CalleeFunctionInfo callee_info)
-> clang::StmtResult {
// TODO: Consider building a CompoundStmt holding our created statement to
// make our result more closely resemble a real C++ function.
clang::SourceLocation clang_loc = callee_info.decl->getLocation();
// If the callee has an object parameter, build a member access expression as
// the callee. Otherwise, build a regular reference to the function.
clang::ExprResult callee;
@@ -569,7 +568,8 @@ static auto BuildThunkBody(CppContext& cpp_context, clang::Sema& sema,
object.get(), IsArrow, clang_loc, clang::NestedNameSpecifierLoc(),
clang::SourceLocation(), callee_info.decl,
clang::DeclAccessPair::make(callee_info.decl, clang::AS_public),
/*HadMultipleCandidates=*/false, clang::DeclarationNameInfo(),
/*HadMultipleCandidates=*/false,
clang::DeclarationNameInfo(callee_info.decl->getDeclName(), clang_loc),
sema.getASTContext().BoundMemberTy, clang::VK_PRValue,
clang::OK_Ordinary);
} else if (!isa<clang::CXXConstructorDecl>(callee_info.decl)) {
@@ -659,18 +659,22 @@ auto BuildCppThunk(Context& context, const SemIR::Function& callee_function)
context.clang_decl_signatures().Get(clang_decl_key.signature_id);
CalleeFunctionInfo callee_info(callee_function_decl, &signature);
clang::SourceLocation clang_loc = callee_function_decl->getLocation();
CARBON_CHECK(clang_loc.isValid(), "Missing location for function");
// Build the thunk function declaration.
auto thunk_param_types =
BuildThunkParameterTypes(context.ast_context(), callee_info);
clang::FunctionDecl* thunk_function_decl =
CreateThunkFunctionDecl(context, callee_info, thunk_param_types);
clang::FunctionDecl* thunk_function_decl = CreateThunkFunctionDecl(
context, callee_info, clang_loc, thunk_param_types);
// Build the thunk function body.
clang::Sema& sema = context.clang_sema();
clang::Sema::ContextRAII context_raii(sema, thunk_function_decl);
sema.ActOnStartOfFunctionDef(nullptr, thunk_function_decl);
clang::StmtResult body = BuildThunkBody(*context.cpp_context(), sema,
thunk_function_decl, callee_info);
clang::StmtResult body =
BuildThunkBody(*context.cpp_context(), sema, clang_loc,
thunk_function_decl, callee_info);
sema.ActOnFinishFunctionBody(thunk_function_decl, body.get());
if (body.isInvalid()) {
return nullptr;