Parser: skip primary function templates in Sema instantiation calls#33
Open
Fedr wants to merge 8 commits into
Open
Parser: skip primary function templates in Sema instantiation calls#33Fedr wants to merge 8 commits into
Fedr wants to merge 8 commits into
Conversation
… / InstantiateFunctionDefinition calls
When the visitor walks a primary `FunctionDecl` for which `decl.isTemplated()`
is true, calling `Sema::InstantiateDefaultArgument` and
`Sema::InstantiateFunctionDefinition` on it is meaningless — there is no
specialization to substitute into — and on every clang version I tested
(18.1.8, 19.1.7, 21.1.8, 22.1.4) both APIs crash with `STATUS_ACCESS_VIOLATION`:
* `Sema::InstantiateDefaultArgument` -> `SubstDefaultArgument` ->
`addInstantiatedParametersToScope`: derefs a `nullptr` returned by
`FunctionDecl::getTemplateInstantiationPattern(/*ForDefinition*/ false)`.
* `Sema::InstantiateFunctionDefinition` -> `FunctionDecl::isDefined()`:
derefs an invalid pattern decl pointer.
The visitor is allowed to see primary templates via `allow_uninstantiated_templates`,
and the specific instantiations are visited separately and handled correctly,
so just skipping the call on primary templates is the right fix.
Reduces to a standalone clang-tooling reproducer:
// repro_input.cpp
template <typename T> struct Wrap {
template <typename U = T> void method(int x = sizeof(U)) {}
};
inline void use() { Wrap<int> w; w.method(); }
// tool: a RecursiveASTVisitor that calls
// Sema::InstantiateDefaultArgument on every ParmVarDecl with
// `hasUninstantiatedDefaultArg()` (no `isTemplated()` guard) crashes
// identically inside libclang. Bug exists at least back to clang 18.1.8.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Fedr
added a commit
to MeshInspector/MeshLib
that referenced
this pull request
May 12, 2026
Picks up the fix that skips primary function templates in `Sema::InstantiateDefaultArgument` / `Sema::InstantiateFunctionDefinition` calls. Without the fix, mrbind parsing `<boost/multiprecision/cpp_int.hpp>` on clang 22 segfaults inside libclang with `STATUS_ACCESS_VIOLATION` on a null `PatternDecl`. See MeshInspector/mrbind#33 for the full repro and stack traces. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Install `llvm::sys::PrintStackTraceOnErrorSignal` at the top of `main()` so a `SIGSEGV` / Windows SEH `STATUS_ACCESS_VIOLATION` from inside libclang prints a backtrace to stderr instead of silently dying. Diagnostic-only — no behavior change on the happy path. With `RelWithDebInfo` builds (already the default per `install_mrbind_windows_msys2.bat`), mrbind frames carry DWARF source locations. libclang-cpp / libLLVM frames show function names only, because msys2 strips DLL debug info. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
adalisk-emikhaylov
added a commit
that referenced
this pull request
May 13, 2026
…mplates-in-sema-calls
…rgs path The block's own comment already says this path is only needed for free function templates and that "something else already instantiates them for the class member functions". When the path is exercised on a CXXMethodDecl (in particular a CXXConstructorDecl), `Sema::SubstDecl` on the member template's pattern null-derefs inside `TemplateDeclInstantiator::InitMethodInstantiation`. Captured stack from CI (clang 22.1.4) parsing `<boost/multiprecision/cpp_int.hpp>` with `--buggy-substitute-default-template-args`: #0 clang::TemplateDeclInstantiator::InitMethodInstantiation #1 clang::TemplateDeclInstantiator::VisitCXXMethodDecl #2 lambda inside Sema::SubstDecl (runWithSufficientStackSpace) #3 clang::StackExhaustionHandler::runWithSufficientStackSpace #4 clang::Sema::runWithSufficientStackSpace #5 clang::Sema::SubstDecl #6 mrbind::ClangAstVisitor_InstTypesAndCollectNewTypes::VisitFunctionDecl main.cpp:2815 <- this call site #7 clang::RecursiveASTVisitor::TraverseCXXConstructorDecl Adding `!llvm::isa<clang::CXXMethodDecl>(decl)` to the existing `decl->isTemplated()` check matches the comment and avoids the crash. This is consistent with the previous commit, which skipped primary function templates from `InstantiateDefaultArgument` / `InstantiateFunctionDefinition` for the same class of latent libclang bug (public Sema API null-derefs on a primary template's pattern). Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
8f5d884 to
c75830f
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The visitor unconditionally called
Sema::InstantiateDefaultArgumentandSema::InstantiateFunctionDefinitionon everyFunctionDeclit traversed, including primary function templates that pass through because ofallow_uninstantiated_templates. On a primary template both APIs null-deref inside libclang and crash withSTATUS_ACCESS_VIOLATION. Skipping the call whendecl.isTemplated()is true fixes both crashes — the specific instantiations are visited separately and processed correctly.Stack traces (clang 22.1.4, MSYS2 mingw-w64-clang-x86_64)
InstantiateDefaultArgumentatmain.cpp:2838:InstantiateFunctionDefinitionatmain.cpp:1072:Both inputs the same:
PatternFDreturned byFunctionDecl::getTemplateInstantiationPattern(/*ForDefinition*/ false)on a primary template is null, and Sema dereferences it without a guard.Tested clang versions
Source-diff of
Sema::SubstDefaultArgument,Sema::addInstantiatedParametersToScope,Sema::InstantiateDefaultArgument,FunctionDecl::getTemplateInstantiationPatternacrossllvmorg-18.1.8 ... llvmorg-22.1.4is logically identical (only type/RAII renames), so the bug is at least as old as v18.Standalone clang-tooling reproducer (no mrbind dependency):
A
RecursiveASTVisitorwhoseVisitFunctionDeclcallsSema::InstantiateDefaultArgumenton everyParmVarDeclwithhasUninstantiatedDefaultArg()(noisTemplated()guard) crashes identically inside libclang. Will be filed upstream against LLVM as API hardening (Sema::InstantiateDefaultArgument's documented precondition is onlyassert(Param->hasUninstantiatedDefaultArg())— it should also assertFD->isTemplateInstantiation()or fail gracefully on a null pattern).Verification on real input
Local mrbind build with this fix, parsing
#include <boost/multiprecision/cpp_int.hpp>on clang 22.1.4:_Complex _Float16— that's a different issue in a different library, not addressed here.Test plan
test/).STATUS_ACCESS_VIOLATIONsegfault duringGenerate C bindings.