Add testcases for concept constrained overload by arity, member operator
overloads, structural partial specialization with a requires-clause, and
the concept only function template redefinition that trips warning 302
(errors/cpp_concept_redefinition). Document existing support for
constrained class templates and member function templates of plain
classes, and the limitations around constraint subsumption: same-
signature templates differing only by requires-clause are dropped, and
concept only "partial specializations" are not selected.
Assisted-by: Claude Code (Opus 4.7)
The constraint subtree built by the parser was previously appended as
the host node's first child, which placed it among class members and
made it appear to take part in scoping. Move it onto a "constraint"
attribute on the host (cdecl, class, template, concept, constructor)
so it is metadata about the declaration, mirroring how parameter lists
live on "parms".
Source/Swig/tree.c: Swig_print_node renders the "constraint" attribute
through Constraint_str, displaying the structured tree as a quoted
C++20 source string the same way ParmList_str_defaultargs renders
"parms". -debug-top / -debug-module dumps now show entries like:
| constraint - 'Numeric< int > && Sized< int >'
Source/CParse/parser.y, templ.c, cscanner.c: the four attachment
points (c_decl, cpp_template_decl prefix and trailing combine,
cpp_concept_decl, and the constructor path) Setattr on "constraint"
instead of appendChild. The %template substitution walker reads
"constraint" via Getattr on cdecl, class, and constructor branches
rather than walking children for it.
copy_node() in parser.y is taught to deep copy the "constraint"
attribute via a recursive copy_node call. Without this the shallow
Copy() at the catchall branch only duplicates the root hash, leaving
inner atom / requires-expression / requirement nodes aliased between
the primary and every instantiation. cparse_template_expand patches
the subtree in place, so the first instantiation's T => int
substitution leaks into every later instantiation - e.g. sum_all_ddd
would print 'AllNumeric< int,int,int >' after sum_all_iii had run.
Source/Modules/lang.cxx: drop the no-op dispatcher entries for
"constraint" / "requires-expression" / "requirement" - they are no
longer reached via the children chain.
The constraint atom for a concept-id used to hold the SwigType-
encoded identifier on a "name" attribute. It is a SwigType, not an
identifier, so rename it to "type" in parser.y, cscanner.c, the
constraint renderer, and the substitution walker. templ.c now feeds
the concept-id type to typelist (the SwigType aware substitution
list) rather than cpatchlist (text only). The renderer decodes the
SwigType back to source form via SwigType_str, so dumps show
'Numeric< int >' rather than the encoded 'Numeric<(int)>'.
The dead render_template_args helper and the unused "templateargs"
ParmList attribute mentioned in early documentation are removed; the
concept-id type already carries the full identifier including the
template-argument list.
CheckedBox(T v) requires Numeric<T> : value(v) {} previously lost its
constraint because ctor_end did not propagate cpp_const.constraint_node
and cpp_constructor_decl did not Setattr it. Add a constraint_node
field to struct Decl, propagate it through both cpp_const-bearing
ctor_end alternatives, and attach it on the constructor node. The
templ.c constructor branch recurses into the new "constraint"
attribute so the trailing requires-clause is substituted at %template
time.
Examples/test suite/cpp20_concepts_classes.i and the python and Java
runme files: add a CheckedBox<double> instantiation to exercise the
constructor's constraint substitution with a different Numeric type.
Assisted-by: Claude Code (Opus 4.7)
A new cpp20_concepts_extra.i test case covers C++20 constraint primary
forms not previously exercised by the suite:
- identity_non_numeric<T> '(!Numeric<T>)' - negation only legal
when wrapped in parens
- mix_add<T,U> multi parameter requires-expression
binding two unrelated template parameters
- AllNumeric<Ts...> variadic concept defined by a fold-
expression over '&&'
- sum_all<T,Rest...> variadic function template constrained
by the variadic concept
- trait_primary<T> 'std::is_integral_v<T>' as a constraint
atom (non-concept-id boolean primary)
- deeper<T> deeper nesting of '&&' / '||' across
multiple parens levels
cpp20_concepts_classes.i gains an OutOfLineBox<T> case: the member
function template scaled<U> is declared in class with
'requires Numeric<U>' and defined out of line with the same prefix
requires-clause on its own template head, exercising the
requires_clause_opt path on a doubly templated declaration.
Matching Python and Java runme files validate the wrapped behaviour;
both new test cases are registered in Examples/test suite/common.mk
under CPP20_TEST_CASES.
No SWIG source changes are needed - the existing scanner level
constraint text capture handles every form added here. The tests
serve as a baseline before the planned structural rework of the
constraint representation.
Assisted-by: Claude Code (Opus 4.7)
Two new test cases extend existing concept coverage from free function
templates to member function templates and class templates, with
matching Python and Java runme files.
cpp20_concepts_class_methods.i - member function templates of a
non-templated Calculator class:
- cube<T> trailing requires-clause
- quad<T> prefix requires-clause
- sum<T> static method, trailing requires with an inline
requires-expression as the constraint
- addn<T> prefix requires using a named concept whose body is
itself a requires-expression
- scale<T,U> two template parameters with a compound '&&' constraint
cpp20_concepts_classes.i - concepts on class templates:
- NumericBox<T> class template with a prefix requires-clause on
the template head
- Holder<T> unconstrained class whose ordinary method
(doubled()) carries its own trailing requires-clause
- SmallBox<T> class template with a compound '&&' prefix
requires-clause
- CheckedBox<T> unconstrained class template with a constrained
constructor
Both new test cases are registered in Examples/test suite/common.mk
under CPP20_TEST_CASES.
Assisted-by: Claude Code (Opus 4.7)