Date: | 2017-06-16 |
Project: | C++ Extensions for Concepts |
Reply to: | Andrew Sutton <asutton@uakron.edu> |
Revised 2017-06-16 at 16:06:02 UTC
Reference ISO/IEC TS 19217
This document contains the C++ core language issues for the Concepts Technical specification which the Committee (INCITS PL22.16 + WG21) has not yet acted, that is, issues with status Ready, Tentatively Ready, Review, Drafing, Open, and New. (See Issue Status below).
This document is part of a group of related documents that together describe the issues that have been raised regarding the C++ Standard. The other documents in the group are:
Section references in this document refelct the section numbering in document WG21 N4549.
The purpose of these documents is to record the disposition of issues that have come before the Core Language Working Group of the ANSI (INCITS PL22.16) and ISO (WG21) C++ Standard Committee.
The issues in these lists are not necessarily formal ISO Defect Reports (DR's). While some issues will eventually be elevated to official Defect Report status, other issues will be disposed of in other ways.
For the most current official version of this document see http://www.open-std.org/jtc1/sc22/wg21/. Requests for further information about this document should include the document number above, reference ISO/IEC 19217, and be submitted to Information Technology Industry Council (ITI), 1250 Eye Street NW, Washington, DC 20005.
Information regarding C++ standardization can be found at http://isocpp.org/std.
Issues progress through various statuses as the Core Language Working Group and, ultimately, the full PL22.16 and WG21 committees deliberate and act. For ease of reference, issues are grouped in these documents by their status. Issues have one of the following statuses:
Open: The issue is new or the working group has not yet formed an opinion on the issue. If a Suggested Resolution is given, it reflects the opinion of the issue's submitter, not necessarily that of the working group or the Committee as a whole.
Drafting: Informal consensus has been reached in the working group and is described in rough terms in a Tentative Resolution, although precise wording for the change is not yet available.
Review: Exact wording of a Proposed Resolution is now available for an issue on which the working group previously reached informal consensus.
Ready: The working group has reached consensus that a change in the working draft is required, the Proposed Resolution is correct, and the issue is ready to forward to the full Committee for ratification.
Tentatively Ready: Like "ready" except that the resolution was produced and approved by a subset of the working group membership between meetings. Persons not participating in these between-meeting activities are encouraged to review such resolutions carefully and to alert the working group with any problems that may be found.
DR: The full Committee has approved the item as a proposed defect report. The Proposed Resolution in an issue with this status reflects the best judgment of the Committee at this time regarding the action that will be taken to remedy the defect; however, the current wording of the Standard remains in effect until such time as a Technical Corrigendum or a revision of the Standard is issued by ISO.
Accepted: Like a DR except that the issue concerns the wording of the current Working Paper rather than that of the current International Standard.
WP: An Accepted issue whose resolution is reflected in the current Working Paper.
Dup: The issue is identical to or a subset of another issue, identified in a Rationale statement.
NAD: The working group has reached consensus that the issue is not a defect in the Standard. A Rationale statement describes the working group's reasoning.
Extension: The working group has reached consensus that the issue is not a defect in the Standard but is a request for an extension to the language. The working group expresses no opinion on the merits of an issue with this status; however, the issue will be maintained on the list for possible future consideration as an extension proposal.
Section: 14.10.1.1 [temp.constr.conv] Status: Open Submitter: CA Opened: 2015-05-18 Last modified: 2017-06-12
View all other issues in [temp.constr.conv].
View all issues with Open status.
Discussion:
More a suggestion than a comment: would a convertible-to-type example like the following be appropriate?
template <typename T> concept bool D =
requires (T a) {
{ a } -> int; // equivalent to std::is_convertible<T,int>::value ?
};
It could be here or in 14.10.1.6, but I get the feeling it would follow the
a==b
example nicely. There is something similar in the middle of the page,
with concept C2, but it is more involved and contributes something else to
reader comprehension.
During discussion in the July telecon, it was determined that there
is a CWG issue related to this request. In particular, it is not
obvious whether access checking was always applied or whether it
depending on the context in which the constraint was evaluated.
Unfortunately, the minutes did not capture which issue.
Section: 7.1.7 [dcl.spec.concept] Status: EWG Submitter: US Opened: 2015-05-18 Last modified: 2017-06-12
View other active issues in [dcl.spec.concept].
View all other issues in [dcl.spec.concept].
View all issues with EWG status.
Discussion:
Using concept
as a decl-specifer, rather than forming a first class
entity like a type or template, makes the feature appear more complex than
it needs to be. Concepts would be simpler (for user and [we believe]
the specification) if there was only one kind, rather than both function
and variable syntax; the bool
keyword would become redundant and the
set of restrictions on concepts based on them being functions or variables
would disappear.
We will provide a paper in time for the Lenexa pre meeting mailing
proposing a grammar that would give all concepts the form:
template <typename T>
concept C = predicate;
Also see issues 7 and 8 as they relate.
EWG is generally in favor of resolving this and related issues, but there is no consensus on how to procdeed.
Section: 7.1.7 [dcl.spec.concept] Status: EWG Submitter: US Opened: 2015-05-18 Last modified: 2017-06-12
View other active issues in [dcl.spec.concept].
View all other issues in [dcl.spec.concept].
View all issues with EWG status.
Discussion:
The syntactic distinction between a function concept and a variable concept seems to serve no useful purpose. A single concept syntax seems sufficient, and especially so once redundant elements are removed. Merge the two concept forms into one, streamlining the syntax by eliminating at least the following redundant elements: explicit bool (see comment below), explicit return, and the always empty parentheses constituting the function parameter list.
Also see issues 6 and 8 as they relate.
EWG is generally in favor of resolving this and related issues, but there is no consensus on how to procdeed.
Section: 7.1.7 [dcl.spec.concept] Status: EWG Submitter: US Opened: 2015-05-18 Last modified: 2017-06-12
View other active issues in [dcl.spec.concept].
View all other issues in [dcl.spec.concept].
View all issues with EWG status.
Discussion:
Since a concept's type always must be bool
, there seems little reason to
require the source code to say so explicitly. Typing concept should be
sufficient without also typing bool immediately afterward.
Allow the compiler to supply bool (a) as the implicit return type for a
function concept and (b) as the implicit type for a variable concept. (Note:
this comment is implicitly accepted if issue 7 is accepted.)
Also see issues 6 and 7 as they relate.
EWG is generally in favor of resolving this and related issues, but there is no consensus on how to procdeed.
Section: 14.10.2 [temp.constr.decl] Status: Open Submitter: US Opened: 2015-05-18 Last modified: 2017-06-12
View other active issues in [temp.constr.decl].
View all other issues in [temp.constr.decl].
View all issues with Open status.
Discussion:
We have a broad concern that it is hard to understand the feature purely from the specification, especially the subsumption rules, and equivalence rules to know when two signatures declare the same function or are ambiguous equally constrained overloads, yet there is a lack of readily available implementations to test our understanding against. While the feature set of the TS looks good, we think one more iteration on the specification would be useful. Proposed solution: Recast the rules for subsumption as a mini grammar (distinct from the C++ grammar) as the English text appears to be trying to describe a grammar, but less formally, which leads to a potential lack of precision, and more confusion for the reader. We are not highlighting specific lack of precision at this time, as we have not emerged from confusion in time to file appropriate comments.
EWG believes this is strictly a wording issue. Returned to CWG.
Section: 5.1.4 [expr.prim.req] Status: EWG Submitter: Casey Carter Opened: 2015-05-28 Last modified: 2017-06-12
View all other issues in [expr.prim.req].
View all issues with EWG status.
Discussion:
It is unclear whether parameter types in a requires-expression are adjusted in the same way that parameter types for functions are adjusted.
Andrew Sutton says that it should be the case.
The TS editor has moved the issue back to EWG for discussion. If requires-parameters are adjusted in the same way that function parameters are adjusted, then we lose information within the concept; top-level cv-qualifiers are removed, types decay, etc.
Wording available:
Add the following sentence to 5.1.4/5:
The types of parameters declared in a requires-expression are adjusted according to the rules for forming funcion types in 8.3.5.
Section: 14.4.3 [temp.arg.template] Status: EWG Submitter: Roland Bock Opened: 2015-10-02 Last modified: 2017-06-12
View all issues with EWG status.
Discussion:
Consider a template that takes a std::tuple
and copies its arguments
into another template (sink), see attached code.
template<typename Tuple, template<typename...> class Sink>
using copy_tuple_args = ...
The copy_tuple_args
template is generic, not caring about the nature
of the copied arguments or the sink. This works fine as long as the
sink is not constrained, e.g. if the sink is another tuple. But a
constrained sink like this
template<Column... C>
struct column_list;
is not allowed according to the working paper since it is more
constrained than the template parameter above. My copy_tuple_arg
template will suddenly cease to work when I start to use concepts.
Wording available:
Modify [temp.arg.template]:
A template-argument (call it A) matches a template template-parameter (call it P) when each of the template parameters in the template-parameter-list of the template-argument's corresponding class template or alias template(call it A)matches the corresponding template parameter in the template-parameter-list of P, and P is either unconstrained or at least as constrained as A according to the rules in 14.10.3.
Section: 7.1.7 [dcl.spec.concept] Status: Open Submitter: Hubert Tong Opened: 2015-10-02 Last modified: 2017-06-12
View other active issues in [dcl.spec.concept].
View all other issues in [dcl.spec.concept].
View all issues with Open status.
Discussion:
Partial specialization of a concept definition is prohibited by 7.1.7 [dcl.spec.concept]p7; however, there appears to be no prohibition on a concept definition which is a partial specialization. e.g.,
template <typename T, typename U> bool C = true;
template <typename U> concept bool C<int, U> = false;
Section: 7.1.7 [dcl.spec.concept] Status: Open Submitter: Hubert Tong Opened: 2015-07-09 Last modified: 2017-06-12
View other active issues in [dcl.spec.concept].
View all other issues in [dcl.spec.concept].
View all issues with Open status.
Discussion:
It seems this is valid, and it is not clear if that is the intent.
namespace A {
template <typename T> extern const bool C;
};
template <typename T> concept bool A::C = true;
Note: The C++14 restriction (removed in DR 1712) that the constexpr specifier be present on every declaration of a variable template if any declaration has the constexpr specifier applies to the "physical" presence of the specifier.
Note: The first declaration of A::C is not a "variable concept". There is no restriction that a variable concept (i.e., "[a] variable template definition having the concept specifier") is the only declaration of the entity that it defines.
This seems to be a more general problem that being a "concept" is not a property of the entity, but of its definition.
Andrew Sutton: This should not be a valid definition.
Section: 14.10.3 [temp.constr.order] Status: Open Submitter: Hubert Tong Opened: 2015-05-25 Last modified: 2017-06-12
View other active issues in [temp.constr.order].
View all other issues in [temp.constr.order].
View all issues with Open status.
Discussion:
The wording in N4377 subclause 14.10.3 [temp.constr.order] bullet 2.2 reads:
Given "A and B" as P0, and "A" as Q0; then my reading of the "each subsumes any" wording is that P0 subsumes Q0 if and only if each atomic constraint in P0 (that is, A and B) subsumes A. That is: (A subsumes A) and (B subsumes A).
I believe the intent is that Pi subsumes Qj if and only if there exists an atomic constraint, Pia, in Pi for which there exists an atomic constraint, Qjb, in Qj such that Pia subsumes Qjb. I am not seeing a way to reconcile the current wording of bullet 2.2 with what I believe the intent is.
Also see issue 30. Addressing that issue will also close this one.
Section: 7.1.7 [dcl.spec.concept] Status: Open Submitter: Hubert Tong Opened: 2015-05-26 Last modified: 2017-06-12
View other active issues in [dcl.spec.concept].
View all other issues in [dcl.spec.concept].
View all issues with Open status.
Discussion:
The word "constant" only appears once in normative text in N4377. It is unclear to me whether a predicate constraint that is not a constant-expression is ill-formed (which would require a diagnostic for a non-temploid function with a requires-clause whose expression is not constant), or merely not satisfied.
It is useful to note that the "ill-formed" position leads to further issues
where constant-expressions of the form P || Q
may be written such that
normalization of constraints will form P or Q where Q is a
predicate constraint whose expression is not a constant-expression.
Faisal Vali, Andrew Sutton, and Gabriel Dos Reis agree that predicate constraints containing non-constant expressions should be ill-formed.
Andrew Sutton suggests: If Q is not dependent and not a constant expression, then the program would be ill-formed. Otherwise if, as a result of substituting during satisfaction, Q is not a constant expression the program is ill-formed.
However, if Q is dependent but never evaluated (because P is
satisfied), the program is well-formed. This would be the same if
substitution into Q would result in substitution failures (e.g., if Q
is X<T>::value
).
Section: 8.4.1 [dcl.fct.def.general] Status: Open Submitter: Hubert Tong Opened: 2015-06-04 Last modified: 2017-06-12
View all issues with Open status.
Discussion:
In N4141 (C++14) subclause [dcl.fct.def.general] paragraph 2: The declarator in a function-definition shall have the form
D1 ( parameter-declaration-clause ) cv-qualifier-seqopt ref-qualifieropt exception-specificationopt attribute-specifier-seqopt trailing-return-typeoptas described in 8.3.5. A function shall be defined only in namespace or class scope.
The issue also occurs in N4141 subclause 12.1 [class.ctor] paragraph 1 and subclause 12.4 [class.dtor] paragraph 1.
Section: 7.1.7 [dcl.spec.concept] Status: EWG Submitter: Hubert Tong Opened: 2015-06-12 Last modified: 2017-06-12
View other active issues in [dcl.spec.concept].
View all other issues in [dcl.spec.concept].
View all issues with EWG status.
Discussion:
An identifier is a concept-name if it refers to a set of concept definitions (7.1.7). Given the following, is C a concept-name?
template <typename T> concept bool C() { return true; }
template <typename T> int C(T t) { return 42; }
struct A { };
bool operator &&(A, int (*)(int));
bool operator &&(A, bool);
bool f(A a) { return a && C<int>; }
It seems that it is not a concept-name since it refers to a set of declarations
which does not contain only concept definitions. If that is the intent, it
should be made more clear.
Section: 8.3.5 [dcl.fct] Status: Open Submitter: Hubert Tong Opened: 2015-06-08 Last modified: 2017-06-12
View all issues with Open status.
Discussion:
There is no disambiguation rule in C++14 PDTS 19217 which requires a type-specifier-seq to consume as many type-specifiers as is available and avoid backtracking.
Given either
template <typename T> requires (bool)&T::operator short
unsigned int foo();
or
template <typename T> requires (bool)sizeof new (T::f()) short
unsigned int bar();
there is more than one successful parse and it is unclear whether the return
type is unsigned int
or int
.
The after-the-function-declarator form of the requires-clause is also ambiguous:
struct X {};
template<typename T> void f() requires (bool)sizeof new X
{
// might be the function body, might be a brace-or-equal-init for X
};
A 'max munch' rule would probably do the wrong thing for the above case,
and likewise here:
template<typename T> requires (bool)sizeof new unsigned
struct X { };
Proposed resolutions have been to:
Section: 7.1.7 [dcl.spec.concept] Status: Open Submitter: Hubert Tong Opened: 2015-06-19 Last modified: 2017-06-12
View other active issues in [dcl.spec.concept].
View all other issues in [dcl.spec.concept].
View all issues with Open status.
Discussion:
Initializers [dcl.init] are not expressions. However bullet 6.3 in [dcl.spec.concept] has a requirement where an "initializer shall be a constraint-expression".
Presumably the constraint is that the initializer shall have exactly one full- expression (that is,
template <typename T> concept bool C{};
is ill-formed), and that said full-expression is valid where a
constraint-expression is required.
It also seems that C++14 subclause 8.5 [dcl.init] paragraph 2 should be removed or updated to exclude objects declared with the concept specifier in a manner similar to how it excludes objects declared with the constexpr specifier.
Section: 14.10.2 [temp.constr.decl] Status: Open Submitter: Hubert Tong Opened: 2015-06-27 Last modified: 2017-06-12
View other active issues in [temp.constr.decl].
View all other issues in [temp.constr.decl].
View all issues with Open status.
Discussion:
The definition of "associated constraints" is in 14.10.2 [temp.constr.decl] paragraph 2 of N4377. Said definition only applies to templates, thus the "associated constraints" being referred to by N4377 subclause 1.3.1 [defns.signature] appears to be undefined.
Section: 14.10.3 [temp.constr.order] Status: Open Submitter: Hubert Tong Opened: 2015-06-27 Last modified: 2017-06-12
View other active issues in [temp.constr.order].
View all other issues in [temp.constr.order].
View all issues with Open status.
Discussion:
Consider the following case:
template <typename T> constexpr bool P = true;
constexpr bool Q = true;
template <typename T = int> requires P<T>
void foo(int = 0, T = 0);
template <typename U = int> requires P<U> && Q
void foo(U = 0, int = 0);
void bar() { foo(); }
It seems that <T>
in the first declaration of
foo()
may be considered equivalent to P<U> in
the second declaration of foo()
; however, I would find it surprising if the call
to foo()
is unambiguous. Note that T
and U
are not involved in the partial ordering in this case aside from the determination
of the more constrained template.
Section: 14.10.3 [temp.constr.order] Status: Open Submitter: Hubert Tong Opened: 2015-06-03 Last modified: 2017-06-12
View other active issues in [temp.constr.order].
View all other issues in [temp.constr.order].
View all issues with Open status.
Discussion:
The following constraint in Clause 14 [temp] is insufficient to prevent the declaration of an abbreviated function template at block scope:
A template-declaration can appear only as a namespace scope or class scope declaration.
Section: 7.1.7 [dcl.spec.concept] Status: Open Submitter: Nathan Wilson Opened: 2015-10-17 Last modified: 2017-06-12
View other active issues in [dcl.spec.concept].
View all other issues in [dcl.spec.concept].
View all issues with Open status.
Discussion:
According to subclause 7.1.7 [dcl.spec.concept] paragraph 5:
A function concept has the following restrictions: (5.1):Would that be redundant because of the restriction on function-specifiers being covered by subsection [dcl.spec.concept]p2 and the result of [dcl.spec.concept]p1, specifically, "The concept specifier shall be applied only to the definition of a function or variable template, declared in namespace scope"?
- No function-specifiers shall appear in its declaration (7.1.2).
- ...
Wording available:
Strike the first bullet in [dcl.spec.concept]p5.
No function-specifiers shall appear in its declaration (7.1.2).- ...
Section: 14.10.3 [temp.constr.order] Status: Open Submitter: Robert Haberlach Opened: 2016-01-23 Last modified: 2017-06-16
View other active issues in [temp.constr.order].
View all other issues in [temp.constr.order].
View all issues with Open status.
Discussion:
Partial ordering by constraints doesn't regard fold expressions.
template <class T> concept bool A = std::is_move_constructible<T>::value;
template <class T> concept bool B = std::is_copy_constructible<T>::value;
template <class T> concept bool C = A<T> && B<T>;
template <class... _tx>
requires (A<_tx> && ...)
void g(_tx... tx) {
std::cout << "a\n";
}
template <class... _tx>
requires (C<_tx> && ...)
void g(_tx... tx) {
std::cout << "c\n";
}
Andrew Sutton: this is logically valid and seems like a reasonable extension. As a general rule, there may be many ways in which we can extend the constraint language to support these kinds of resolutions. Of course, this means that each such change potentially breaks changes.
This needs to apply to expansions of disjunctions also. This is done by inverting the subsumption (i.e., when Q subsumes P).
Wording available:
Augment 14.10.3 [temp.constr.order]p(2.3) thusly: an atomic constraint A subsumes another atomic constraint B if and only if either(P && ...)
and B is of the form (Q && ...)
or (Q || ...)
, where P
subsumes Q
..
Section: 14.10.2 [temp.constr.decl] Status: Open Submitter: Andrew Sutton Opened: 2016-02-27 Last modified: 2017-06-12
View other active issues in [temp.constr.decl].
View all other issues in [temp.constr.decl].
View all issues with Open status.
Discussion:
The current wording for normalization guarantees exponential performance during subsumption.
Addressing this issue first requires that we address issue 29. If concepts can be safely evaluated in any context, then we do not need to lift the entire constraint into the current instantiation.
The current phrasing also prohibits certain compiler optimizations by requiring a full expansion to atomic constraints. In particular, this does not admit early termination of the algorithm or memoization of comparisons.
Prior to the Skillman concepts meeting, there was a much more abstract wording for the subsumption algorithm. One resolution would be to revert the current wording to the older version.
Wording available:
Section: 7.1.6.4.2 [dcl.spec.auto.constr] Status: Open Submitter: Jason Merrill Opened: 2016-03-03 Last modified: 2017-06-12
View all other issues in [dcl.spec.auto.constr].
View all issues with Open status.
Discussion:
A constrained-type-specifier also denotes non-type constraints. The production name should reflect that.
Section: 14.2 [temp.intro] Status: New Submitter: Hubert Tong Opened: 2016-05-04 Last modified: 2017-06-12
View all issues with New status.
Discussion:
There appear to be no semantics applied to the use of a partial-concept-id as the qualified-concept-name in a template-introduction. In particular, N4552 subclause 14.2 [temp.intro] refers to subclause 14.10.4 [temp.constr.resolve], which in turn does not specify what the concept argument list is in such a case.
Andrew Sutton: "disallowing this seems reasonable".
Wording available:
Section: 14.6.4 [temp.friend] Status: New Submitter: Hubert Tong Opened: 2016-05-06 Last modified: 2017-06-12
View all issues with New status.
Discussion:
Given:
template <typename T>
requires true || T::happy
void foo(T &&) { }
template <typename T>
struct A {
friend void bar(A &&)
requires true || T::happy {
}
};
int main(void) {
foo(0);
bar(A<int>());
}
there appears to be wording (normative and otherwise), which would render the
program ill-formed. I assume that is not the intent.
The wording involved is as follows: N4553 subclause 14.6.4 [temp.friend] paragraph 11: In the instantiation of such a class template (14.8), the template arguments are substituted into the constraints but not evaluated. [ ... ] If substitution fails, the program is ill-formed.
N4553 subclause 14.9.2 [temp.deduct] paragraph 5: If the function template has associated constraints (14.10.2), the template arguments are substituted into the associated constraints without evaluating the resulting expression. If this substitution results in an invalid type or expression, type deduction fails.
Wording available:
Section: 14.10.1 [temp.constr.constr] Status: New Submitter: Hubert Tong Opened: 2016-05-06 Last modified: 2017-06-12
View all issues with New status.
Discussion:
The TS often refers to substitution or instantiation of associated constraints;
however, associated constraints are a derived property of what might be called
"constraining elements", i.e., constrained-type-specifiers, constrained-
parameters, template-introductions and constraint-expressions.
It appears that the wording in N4553 subclause 14.10.1 [temp.constr.constr]
is attempting to achieve "partial substitution" is trumped in many cases by
substitution into constraining elements.
For example, the associated constraints would evaluate false (or in a more
realistic case, a check that T::type
is a type) prior to
considering C<placeholder, typename T::type>()
, but it is unclear
whether instantiating A<int>
causes an error from the use of
T::type
:
template <typename T, typename U>
concept bool C() { return true; }
template <typename T>
struct A {
template <typename U> requires false
void foo(C<typename T::type>) { }
};
int main(void) { A<int> a; }
Wording available:
Section: 14 [temp] Status: New Submitter: Walter Brown Opened: 2016-08-31 Last modified: 2017-06-16
View all issues with New status.
Discussion:
Concepts allow constraints on non-template functions but not on explicit specializations of class templates. For example:
template<>
requires numeric_has_infinity_v<double>
struct
infinity_unqual<double>
{
static constexpr double value = __builtin_inf();
};
Wording available:
bool
requirement on predicate constraintsSection: 14.10.1.1 [temp.constr.pred] Status: New Submitter: Hubert Tong Opened: 2017-06-08 Last modified: 2017-06-16
View all issues with New status.
Discussion:
The bool
type diagnosable rule on predicate constraints already
encompasses the much more verbose user-declared logical operator rules if we
consistently apply substitution into predicate constraints only when evaluation
of its value for satisfaction is required.
The note in 14.10.1.1 [temp.constr.op] paragraph 6 ignores substitution
failure in its claims of agreement between expression evaluation and
satisfaction.
In 14.10.1.2 [temp.constr.pred] paragraph 1:
After substitution,
In 14.10.1.1 [temp.constr.op] paragraph 2:
E
shall have type bool.
If the left and right operands of a conjunction are predicate
constraints (14.10.1.2), let
In 14.10.1.1 [temp.constr.op] paragraph 4:
P
and Q
be the
expressions of those constraints resulting from substitution.
If the expression P && Q
results in a call to a user-declared
operator&&
, the program is ill-formed.
If the left and right operands of a disjunction are predicate constraints
(14.10.1.2), let
P
and Q
be the expressions of those
constraints resulting from substitution. If the expression P || Q
results in a call to a user-declared operator||
, the program is
ill-formed.
Wording available: