Pass names of non-type entities through as template arg values - #219
Pass names of non-type entities through as template arg values#219conrade-ctc wants to merge 2 commits into
Conversation
A string template arg naming a constexpr variable or enum constant used
to resolve to the entity's type, so Sema rejected it for non-type
parameters ("must be an expression"). Pass the qualified name in
m_IntegralValue instead; CppInterOp turns it into a reference.
Co-developed-with-the-help-of: Claude Code (Fable 5, human in the loop)
|
Companion to the compiler-research/CppInterOp#1074 update: |
| // true/false are identifier-shaped value literals. | ||
| if (name == "true" || name == "false") { | ||
| types.emplace_back(Cpp::GetType("bool").data, | ||
| strdup(name == "true" ? "1" : "0")); |
There was a problem hiding this comment.
Why do we need a copy of these literals? They are in the data section of the binary so we should not copy them.
There was a problem hiding this comment.
Good catch — dropped the strdup. "1"/"0" are static string literals and TemplateArgInfo only borrows m_IntegralValue, so there is nothing to own.
Class/alias template names become template-template args (carried by name, null type) in both the identifier path and the qualified-name fallback; true/false map to bool values in the identifier fast path; is_integral accepts negative literals. Co-developed-with-the-help-of: Claude Code (Fable 5, human in the loop)
acb803f to
120cf92
Compare
A string template argument naming a constexpr variable or enum constant resolves to the entity's type today:
AppendTypesSlow's identifier path callsCpp::GetType, whoseValueDeclbranch returns the variable's declared type with no value. Sema then sees a type argument for a non-type parameter and rejects the instantiation ("template argument for non-type template parameter must be an expression"):This PR checks
Cpp::GetNamedfirst: when the identifier names a variable or enum constant, it emitsTemplateArgInfo{entity type, strdup(GetQualifiedCompleteName(...))}so the instantiation refers to the entity instead of its type. The comma-split fallback gets the symmetric check, covering qualified spellings ("ns::Val") and multi-argument strings. It also passes class/alias template names through as template-template arguments (null type + qualified name), and fixestrue/falseand negative integer literals in the identifier path (both previously produced a type-only argument that Sema rejected).Requires the companion PR compiler-research/CppInterOp#1074, which teaches
InstantiateTemplate/BestOverloadFunctionMatchto resolve a non-numericm_IntegralValueas a named constant entity (DeclRefExpr, converted by Sema like a written argument). Notes for the FIXME discussion at #137 (comment) : this narrows the string-parsing surface rather than growing it — names are resolved through lookup, not parsed.Intentionally out of scope: arbitrary constant expressions in strings ("IntArg + 1", "&x") — only (possibly qualified) names of constant entities and templates. cppyy
TemplateProxyobjects as template-template arguments now fail with a clean TypeError (previously a segfault via a null-typeIsEnumTypecall); making them work needs a CPyCppyyAddTypeNamechange — left as follow-up.Tests: the conversion logic is unit-tested in the companion CppInterOp PR (
ScopeReflection_InstantiateTemplateNamedNTTPArg); end-to-end coverage in our downstream suite (class templates, function-template explicit args, enum constants, qualified names,const char*array decay). Happy to add atest_templates.pycase to compiler-research/cppyy alongside if preferred.🤖 Done with the help of Claude Code (Fable 5, human in the loop)