Three additional concept / requires-expression tested.
All existing parser support (the requires-expression body
is skipped via skip_balanced):
- Inline 'requires requires' with a compound requirement (add_inline_same).
- A concept body listing multiple simple-requirements (Machine -> cycle).
- A concept body mixing the other three requirement kinds: a
type-requirement, a noexcept compound-requirement and a nested
requires-clause (BasicContainer -> check_container).
A requires-expression body may mix simple-requirements ('expr;')
with compound-requirements that carry a trailing return type
constraint ('{ expr } -> type-constraint;').
Add docs and an example testing this.
This works on existing parser support: the concept declaration is
silently consumed by skip_decl, whose skip_balanced('{', '}') already
handles the nested braces of the compound requirement, and the
trailing 'requires AddableSame<T>' goes through the existing
skip_constraint path
Also add test for 'requires requires' form with compound-requirement.
Show the named concept counterpart to the inline 'requires requires'
form already covered by the cpp20_concepts test case: a concept whose
body is a requires-expression, used as the constraint of a function
template. Distinct name (Summable) so it does not clash with the
Addable variable template in cpp20_variable_templates.
template<typename T>
concept Summable = requires (T t) { t + t; };
template<typename T>
T sum_pair(T a, T b) requires Summable<T> {
return a + b;
}
This works on existing parser support: the concept declaration is
silently consumed by skip_decl, and the trailing 'requires Summable<T>'
goes through the existing skip_constraint path.
A requires-expression of the form 'requires [(parms)] { body }' is one
of the primary forms a C++20 constraint can take, e.g.
template<typename T>
T add(T a, T b) requires requires (T t) { t + t; } {
return a + b;
}
The trailing form skip helper (skip_constraint in cscanner.c) was
walking tokens until it saw '{', ';' or '=' at depth 0 while tracking
only paren and bracket depth. The inner '{ t + t; }' of the
requires-expression body therefore terminated the skip prematurely,
leaving the function body unparsed and producing a spurious syntax
error on the next token.
Teach skip_constraint to recognise a 'requires' identifier at depth 0
and treat it together with its optional '(parms)' and required
'{ body }' as one opaque primary - balancing the body via
Scanner_skip_balanced rather than letting its '{' end the constraint.
The cpp20_concepts test case grows an 'add' function template that
exercises this form, with matching Python and Java runme assertions
checking that add_int(2, 3) == 5 and add_int(-7, 4) == -3. The C++20
manual chapter is updated to move the requires-expression-as-constraint-
primary form from the limitations list back to the supported set; the
'requires-expression bound to a namespace scope variable' form remains
unsupported.
Assisted-by: Claude Code (Opus 4.7)
A C++20 prefix requires-clause sits between the closing '>' of the
template parameter list and the start of the declaration it constrains:
template<typename T> requires Numeric<T> && std::integral<T>
T quad(T x) { return x * x * x * x; }
The previous commit handled the trailing form because the constraint is
followed by exactly one of three terminators ('{', ';' or '=') and a
token level skip helper just reads tokens, balancing '()' and '[]',
until it sees one of those at depth 0 and pushes it back. The prefix
form has no such terminator: after 'requires Numeric<T> && std::integral<T>'
the next token is 'T' - the start of the return type of quad - but 'T'
can also legally appear inside a constraint (e.g. 'Numeric<T>'), so a
pure character level skip cannot tell whether 'T' belongs to the
constraint or to the declarator that follows it.
The C++20 grammar resolves this by defining a constraint as a
constraint-logical-or-expression:
constraint-logical-or-expression:
constraint-logical-and-expression
constraint-logical-or-expression || constraint-logical-and-expression
constraint-logical-and-expression:
primary-expression
constraint-logical-and-expression && primary-expression
After consuming one primary the next token decides everything: if it is
'&&' or '||' another primary follows; otherwise the constraint is over
and that token belongs to the declarator. This commit implements that
loop directly at the scanner level (skip_constraint_primary plus
skip_prefix_requires_clause in cscanner.c) so the bison grammar does
not have to model the constraint expression at all. A primary is a
parenthesised group, a requires-expression, or an id chain optionally
extended with '::' segments and a single template arg list, all of
which are bounded constructs that existing scanner helpers already
balance correctly.
The grammar change is a single new requires_clause_opt nonterminal
inserted between GREATERTHAN and the mid rule action of cpp_template_decl;
its REQUIRES alternative calls skip_prefix_requires_clause and
contributes nothing to the parse tree value. Bison reports no new
shift/reduce conflicts under -Wall -Werror.
Test cases and Python/Java runme files are extended to cover prefix
requires-clauses with bare, '&&'-compounded, and parenthesised forms.
The manual chapter and CHANGES.current entry are updated accordingly.
Assisted-by: Claude Code (Opus 4.7)
Add minimal parser support so SWIG no longer rejects C++20 concept
declarations or function templates with a trailing requires-clause.
Both constructs are silently consumed and produce no parse tree node,
so a constrained function template wraps as if it were unconstrained.
Implementation: new CONCEPT and REQUIRES tokens are recognised in the
C++ scanner alongside final/override. cpp_concept_decl is added to
cpp_template_possible and uses the existing skip_decl() helper to eat
the whole declaration. cpp_const gains two alternatives that consume
a trailing requires-clause via a new skip_constraint() helper, which
reads tokens until top level '{', ';' or '=' while balancing () and [].
Prefix requires-clauses (between the template head and the declarator)
are not yet supported - the constraint terminator in that position
isn't reliably detectable at lex level.
Adds the cpp20_concepts test case (Numeric and SmallNumeric concepts,
a cube function template constrained by a trailing requires-clause,
%template instantiations for int and double), Python and Java runme
files exercising those instantiations, and a Concepts and
requires-clauses section in the C++20 manual chapter (Contents.html
regenerated via make maketoc).
Assisted-by: Claude Code (Opus 4.7)