## Summary Rewrites the template resolver to eliminate `SubstType`/`CodeSynthesisContexts` dependency, fixing widespread crashes on real-world C++ code. ### What changed **Architecture**: replaced double-TreeTransform (PseudoInstantiator + SubstType) with single-layer design: - **`SubstituteOnly`** — new lightweight TreeTransform for Phase 2 (typedef expansion + parameter substitution). Does NOT override `TransformDependentNameType`, breaking the typedef ↔ lookup infinite cycle. - **`PseudoInstantiator`** — retains heuristic lookup (the unique value clang doesn't provide), delegates substitution to `SubstituteOnly`. **Deleted**: - `DesugarOnly` class - `instantiate()` method and all `CodeSynthesisContexts` / `SubstType` usage - `state()` / `rewind()` stack management - `std::abort()` on valid NNS kinds - `#ifndef NDEBUG` debug flag + `std::print` logging **Added**: - `SubstituteOnly` class with depth guard - `InstantiationStack::findArgument()` — depth/index based parameter lookup - CTD→TST resolution for `DependentTemplateSpecializationType` (enables `__alloc_traits::rebind<T>::other` resolution) - `active_resolutions` (DNT cycle detection) + `active_ctd_lookups` (CTD cycle detection via RAII guard) - Stack frame pollution fix: pop lookup frames before further `TransformType` - Pack argument support (single-element forwarding) - Null safety on all Transform return paths - Structured `LOG_DEBUG` trace logging with indentation - `--log-level` / `--test-filter` CLI options for unit test runner - Bounds checks in `hole()`, `ResugarOnly`, `visitTemplateDeclContexts` **Tests**: 20 → 36 passing test cases (+5 documented TODOs for known limitations). New coverage: recursive base classes, multiple inheritance, typedef chains, CRTP, `remove_reference` partial specs, `std::map`, `std::basic_string`, pack forwarding. ### Stress test result ``` CDB: llvm-project build (4669 C++ files) Types resolved: 3,690,190 Types unchanged: 75,907,298 Crashes: 0 ``` Before this PR, the same test produced ~52% crash rate (413 crashes in 800 files). ### Known limitations (documented as TODOs) - NTTP partial specialization matching (`enable_if<true, X>`, `A<X, 0>`) - Template template parameter deduction - Non-dependent qualifier nested class templates (`Outer<int>::Inner<X>`) - Multi-element pack expansion - `CXXDependentScopeMemberExpr` lookup (unimplemented) - Operator-name lookup in dependent contexts 🤖 Generated with [Claude Code](https://claude.com/claude-code) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit ## Release Notes * **New Features** * Enhanced template resolution with improved cycle detection to prevent infinite loops * Better type substitution handling for complex dependent types * **Bug Fixes** * Fixed edge cases in template specialization resolution * Improved null-safety in type transformations * Enhanced handling of standard library template traits * **Tests** * Expanded test coverage for recursive and complex template patterns * Added validation for standard library type resolution <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
59 lines
2.0 KiB
C++
59 lines
2.0 KiB
C++
#include <string>
|
|
#include <string_view>
|
|
|
|
#include "eventide/deco/deco.h"
|
|
#include "eventide/zest/zest.h"
|
|
#include "support/logging.h"
|
|
|
|
namespace {
|
|
|
|
constexpr auto kv_style = static_cast<char>(deco::decl::KVStyle::Joined) |
|
|
static_cast<char>(deco::decl::KVStyle::Separate);
|
|
|
|
struct TestOptions {
|
|
DecoKVStyled(kv_style, names = {"--test-filter", "--test-filter="};
|
|
help = "Filter tests by name";
|
|
required = false;)
|
|
<std::string> test_filter;
|
|
|
|
DecoKVStyled(kv_style, names = {"--log-level", "--log-level="};
|
|
help = "Log level: trace/debug/info/warn/err";
|
|
required = false;)
|
|
<std::string> log_level;
|
|
|
|
DecoKVStyled(kv_style, names = {"--test-dir", "--test-dir="}; help = "Test data directory";
|
|
required = false;)
|
|
<std::string> test_dir;
|
|
};
|
|
|
|
} // namespace
|
|
|
|
int main(int argc, const char** argv) {
|
|
auto args = deco::util::argvify(argc, argv);
|
|
auto parsed = deco::cli::parse<TestOptions>(args);
|
|
|
|
std::string_view filter = {};
|
|
if(parsed.has_value() && parsed->options.test_filter.has_value()) {
|
|
filter = *parsed->options.test_filter;
|
|
}
|
|
|
|
if(parsed.has_value() && parsed->options.log_level.has_value()) {
|
|
auto level = *parsed->options.log_level;
|
|
if(level == "trace") {
|
|
clice::logging::options.level = clice::logging::Level::trace;
|
|
} else if(level == "debug") {
|
|
clice::logging::options.level = clice::logging::Level::debug;
|
|
} else if(level == "info") {
|
|
clice::logging::options.level = clice::logging::Level::info;
|
|
} else if(level == "warn") {
|
|
clice::logging::options.level = clice::logging::Level::warn;
|
|
} else if(level == "err") {
|
|
clice::logging::options.level = clice::logging::Level::err;
|
|
}
|
|
}
|
|
|
|
clice::logging::stderr_logger("test", clice::logging::options);
|
|
|
|
return eventide::zest::Runner::instance().run_tests(filter);
|
|
}
|