From 1231098c144cf1e820b59560df86bc8399f87690 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 20 May 2026 16:18:15 -0700 Subject: [PATCH] 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 --- toolchain/check/cpp/thunk.cpp | 28 +++++++++++-------- .../interop/cpp/class/import/template.carbon | 18 ++++++++++++ 2 files changed, 34 insertions(+), 12 deletions(-) diff --git a/toolchain/check/cpp/thunk.cpp b/toolchain/check/cpp/thunk.cpp index 1a1016a86188..9cbf1419870a 100644 --- a/toolchain/check/cpp/thunk.cpp +++ b/toolchain/check/cpp/thunk.cpp @@ -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::SourceLocation clang_loc = callee_info.decl->getLocation(); - const auto* thunk_function_proto_type = thunk_function_decl->getType()->castAs(); @@ -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 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(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; diff --git a/toolchain/check/testdata/interop/cpp/class/import/template.carbon b/toolchain/check/testdata/interop/cpp/class/import/template.carbon index 777501729828..7398f5544dc9 100644 --- a/toolchain/check/testdata/interop/cpp/class/import/template.carbon +++ b/toolchain/check/testdata/interop/cpp/class/import/template.carbon @@ -80,6 +80,24 @@ var x: Cpp.XY.r#type = 0; var y: Cpp.Xint.r#type = 0; //@dump-sem-ir-end +// --- use_indirect_class_template.carbon + +library "[[@TEST_NAME]]"; + +import Cpp; +inline Cpp ''' +template struct wrap_iter {}; +template struct vector { + using iterator = wrap_iter; + iterator begin(); +}; +'''; + +fn F() { + var v: Cpp.vector(i32); + v.begin(); +} + // CHECK:STDOUT: --- use_class_template.carbon // CHECK:STDOUT: // CHECK:STDOUT: constants {