Skip to content

Commit 0fc2af6

Browse files
jensmaurerzygoloid
authored andcommitted
[dcl.attr.contract] Reorder paragraphs for more coherence.
Also move rules on virtual functions to [class.virtual]. Rephase assertion checking along pre/postcondition checking.
1 parent 42019fd commit 0fc2af6

File tree

2 files changed

+159
-168
lines changed

2 files changed

+159
-168
lines changed

source/declarations.tex

Lines changed: 122 additions & 165 deletions
Original file line numberDiff line numberDiff line change
@@ -4285,6 +4285,17 @@
42854285
It expresses a condition that a function should ensure
42864286
for the return value and/or the state of objects
42874287
using a predicate that is intended to hold upon exit from the function.
4288+
A postcondition may introduce an identifier to represent
4289+
the glvalue result or the prvalue result object of the function.
4290+
\begin{example}
4291+
\begin{codeblock}
4292+
int f(char * c)
4293+
[[ensures res: res > 0 && c != nullptr]];
4294+
4295+
int g(double * p)
4296+
[[ensures audit res: res != 0 && p != nullptr && *p <= 0.0]];
4297+
\end{codeblock}
4298+
\end{example}
42884299

42894300
\pnum
42904301
A \grammarterm{contract-attribute-specifier} using \tcode{assert}
@@ -4333,15 +4344,30 @@
43334344
and template parameters.
43344345

43354346
\pnum
4336-
An assertion is checked by evaluating its predicate.
4337-
The predicate of an assertion is potentially evaluated\iref{basic.def.odr}.
4338-
The predicate of an assertion is evaluated
4339-
as part of the evaluation of the null statement\iref{stmt.expr} it applies to.
4347+
\begin{note}
4348+
A function pointer cannot include contract conditions.
4349+
\begin{example}
4350+
\begin{codeblock}
4351+
typedef int (*fpt)() [[ensures r: r != 0]]; // error: contract condition not on a function declaration
4352+
4353+
int g(int x)
4354+
[[expects: x >= 0]]
4355+
[[ensures r: r > x]]
4356+
{
4357+
return x+1;
4358+
}
4359+
4360+
int (*pf)(int) = g; // OK
4361+
int x = pf(5); // contract conditions of \tcode{g} are checked
4362+
\end{codeblock}
4363+
\end{example}
4364+
\end{note}
43404365

43414366
\pnum
4342-
The predicate of a contract condition
4343-
is potentially evaluated\iref{basic.def.odr}
4344-
and has the same semantic restrictions
4367+
The predicate of a contract is potentially evaluated\iref{basic.def.odr}.
4368+
4369+
\pnum
4370+
The predicate of a contract condition has the same semantic restrictions
43454371
as if it appeared as the first \grammarterm{expression-statement}
43464372
in the body of the function it applies to.
43474373
Additional access restrictions apply to names appearing in
@@ -4391,12 +4417,54 @@
43914417
\end{codeblock}
43924418
\end{example}
43934419

4420+
\pnum
4421+
A precondition is checked by evaluating its predicate
4422+
immediately before starting evaluation of the function body.
4423+
\begin{note}
4424+
The function body includes
4425+
the \grammarterm{function-try-block}\iref{except} and
4426+
the \grammarterm{ctor-initializer}\iref{class.base.init}.
4427+
\end{note}
4428+
A postcondition is checked by evaluating its predicate
4429+
immediately before returning control to the caller of the function.
4430+
\begin{note}
4431+
The lifetime of local variables and temporaries has ended.
4432+
Exiting via an exception or via \tcode{longjmp}\iref{csetjmp.syn}
4433+
is not considered returning control to the caller of the function.
4434+
\end{note}
4435+
4436+
\pnum
4437+
If a function has multiple preconditions,
4438+
their evaluation (if any) will be performed
4439+
in the order they appear lexically.
4440+
If a function has multiple postconditions,
4441+
their evaluation (if any) will be performed
4442+
in the order they appear lexically.
4443+
\begin{example}
4444+
\begin{codeblock}
4445+
void f(int * p)
4446+
[[expects: p != nullptr]] // \#1
4447+
[[ensures: *p == 1]] // \#3
4448+
[[expects: *p == 0]] // \#2
4449+
{
4450+
*p = 1;
4451+
}
4452+
\end{codeblock}
4453+
\end{example}
4454+
4455+
\pnum
4456+
An assertion is checked by evaluating its predicate
4457+
as part of the evaluation of the null statement\iref{stmt.expr}
4458+
it applies to.
4459+
43944460
\pnum
43954461
The only side effects of a predicate
43964462
that are allowed in a \grammarterm{contract-attribute-specifier}
43974463
are modifications of non-volatile objects
43984464
whose lifetime began and ended within the evaluation of the predicate
43994465
in functions invoked from that predicate.
4466+
An evaluation of a predicate that exits via an exception
4467+
invokes \tcode{std::terminate()}\iref{except.terminate}.
44004468
The behavior of any other side effect is undefined.
44014469
\begin{example}
44024470
\begin{codeblock}
@@ -4424,6 +4492,34 @@
44244492
\end{codeblock}
44254493
\end{example}
44264494

4495+
\pnum
4496+
If a postcondition odr-uses\iref{basic.def.odr}
4497+
a parameter value in its predicate
4498+
and the function body makes direct or indirect modifications of that value,
4499+
the behavior is undefined.
4500+
\begin{example}
4501+
\begin{codeblock}
4502+
int f(int x)
4503+
[[ensures r: r == x]]
4504+
{
4505+
return ++x; // undefined behavior
4506+
}
4507+
4508+
int g(int * p)
4509+
[[ensures r: p != nullptr]]
4510+
{
4511+
*p = 42; // OK, \tcode{p} is not modified
4512+
}
4513+
4514+
int h(int x)
4515+
[[ensures r: r == x]]
4516+
{
4517+
potentially_modify(x); // undefined behavior if \tcode{x} is modified
4518+
return x;
4519+
}
4520+
\end{codeblock}
4521+
\end{example}
4522+
44274523
\pnum
44284524
If the \grammarterm{contract-level}
44294525
of a \grammarterm{contract-attribute-specifier} is absent,
@@ -4444,6 +4540,25 @@
44444540
and are not evaluated at run-time.
44454541
\end{note}
44464542

4543+
\pnum
4544+
Multiple contract conditions may be applied to a function type
4545+
with the same or different \grammarterm{contract-level}{s}.
4546+
\begin{example}
4547+
\begin{codeblock}
4548+
int z;
4549+
4550+
bool is_prime(int k);
4551+
4552+
void f(int x)
4553+
[[expects: x > 0]]
4554+
[[expects audit: is_prime(x)]]
4555+
[[ensures: z > 10]]
4556+
{
4557+
@\commentellip@
4558+
}
4559+
\end{codeblock}
4560+
\end{example}
4561+
44474562
\pnum
44484563
A translation may be performed
44494564
with one of the following \defnx{build levels}{build level}:
@@ -4461,43 +4576,6 @@
44614576
There should be no programmatic way of setting, modifying, or querying
44624577
the build level of a translation unit.
44634578

4464-
\pnum
4465-
A precondition is checked by evaluating its predicate
4466-
immediately before starting evaluation of the function body.
4467-
\begin{note}
4468-
The function body includes
4469-
the \grammarterm{function-try-block}\iref{except} and
4470-
the \grammarterm{ctor-initializer}\iref{class.base.init}.
4471-
\end{note}
4472-
A postcondition is checked by evaluating its predicate
4473-
immediately before returning control to the caller of the function.
4474-
\begin{note}
4475-
The lifetime of local variables and temporaries has ended.
4476-
Exiting via an exception or via \tcode{longjmp}\iref{csetjmp.syn}
4477-
is not considered returning control to the caller of the function.
4478-
\end{note}
4479-
An evaluation of a predicate that exits via an exception
4480-
invokes \tcode{std::terminate()}\iref{except.terminate}.
4481-
4482-
\pnum
4483-
If a function has multiple preconditions,
4484-
their evaluation (if any) will be performed
4485-
in the order they appear lexically.
4486-
If a function has multiple postconditions,
4487-
their evaluation (if any) will be performed
4488-
in the order they appear lexically.
4489-
\begin{example}
4490-
\begin{codeblock}
4491-
void f(int * p)
4492-
[[expects: p != nullptr]] // \#1
4493-
[[ensures: *p == 1]] // \#3
4494-
[[expects: *p == 0]] // \#2
4495-
{
4496-
*p = 1;
4497-
}
4498-
\end{codeblock}
4499-
\end{example}
4500-
45014579
\pnum
45024580
It is unspecified whether a contract
45034581
that would not be checked under the current build level is evaluated.
@@ -4577,125 +4655,4 @@
45774655
\end{codeblock}
45784656
\end{example}
45794657

4580-
\rSec3[dcl.attr.contract.iface]{Interface contracts}%
4581-
4582-
\pnum
4583-
Multiple contract conditions may be applied to a function type
4584-
with the same or different \grammarterm{contract-level}{s}.
4585-
\begin{example}
4586-
\begin{codeblock}
4587-
int z;
4588-
4589-
bool is_prime(int k);
4590-
4591-
void f(int x)
4592-
[[expects: x > 0]]
4593-
[[expects audit: is_prime(x)]]
4594-
[[ensures: z > 10]]
4595-
{
4596-
@\commentellip@
4597-
}
4598-
\end{codeblock}
4599-
\end{example}
4600-
4601-
\pnum
4602-
A postcondition may introduce an identifier to represent
4603-
the glvalue result or the prvalue result object of the function.
4604-
\begin{example}
4605-
\begin{codeblock}
4606-
int f(char * c)
4607-
[[ensures res: res > 0 && c != nullptr]];
4608-
4609-
int g(double * p)
4610-
[[ensures audit res: res != 0 && p != nullptr && *p <= 0.0]];
4611-
\end{codeblock}
4612-
\end{example}
4613-
4614-
\pnum
4615-
If a postcondition odr-uses\iref{basic.def.odr}
4616-
a parameter value in its predicate
4617-
and the function body makes direct or indirect modifications of that value,
4618-
the behavior is undefined.
4619-
\begin{example}
4620-
\begin{codeblock}
4621-
int f(int x)
4622-
[[ensures r: r == x]]
4623-
{
4624-
return ++x; // undefined behavior
4625-
}
4626-
4627-
int g(int * p)
4628-
[[ensures r: p != nullptr]]
4629-
{
4630-
*p = 42; // OK, \tcode{p} is not modified
4631-
}
4632-
4633-
int h(int x)
4634-
[[ensures r: r == x]]
4635-
{
4636-
potentially_modify(x); // undefined behavior if \tcode{x} is modified
4637-
return x;
4638-
}
4639-
\end{codeblock}
4640-
\end{example}
4641-
4642-
\pnum
4643-
\begin{note}
4644-
A function pointer cannot include contract conditions.
4645-
\begin{example}
4646-
\begin{codeblock}
4647-
typedef int (*fpt)() [[ensures r: r != 0]]; // error: contract condition not on a function declaration
4648-
4649-
int g(int x)
4650-
[[expects: x >= 0]]
4651-
[[ensures r: r > x]]
4652-
{
4653-
return x+1;
4654-
}
4655-
4656-
int (*pf)(int) = g; // OK
4657-
int x = pf(5); // contract conditions of \tcode{g} are checked
4658-
\end{codeblock}
4659-
\end{example}
4660-
\end{note}
4661-
4662-
\pnum
4663-
If an overriding function specifies contract conditions,
4664-
it shall specify the same list of contract conditions as
4665-
its overridden functions;
4666-
no diagnostic is required
4667-
if corresponding conditions will always evaluate to the same value.
4668-
Otherwise, it is considered to have
4669-
the list of contract conditions from one of its overridden functions;
4670-
the names in the contract conditions are bound,
4671-
and the semantic constraints are checked,
4672-
at the point where the contract conditions appear.
4673-
Given a virtual function \tcode{f}
4674-
with a contract condition that odr-uses \tcode{*this}\iref{basic.def.odr},
4675-
the class of which \tcode{f} is a direct member
4676-
shall be be an unambiguous and accessible base class of any class
4677-
in which \tcode{f} is overridden.
4678-
If a function overrides more than one function,
4679-
all of the overridden functions shall have
4680-
the same list of contract conditions\iref{dcl.attr.contract};
4681-
no diagnostic is required
4682-
if corresponding conditions will always evaluate to the same value.
4683-
\begin{example}
4684-
\begin{codeblock}
4685-
struct A {
4686-
virtual void g() [[expects: x == 0]];
4687-
int x = 42;
4688-
};
4689-
4690-
int x = 42;
4691-
struct B {
4692-
virtual void g() [[expects: x == 0]];
4693-
}
4694-
4695-
struct C : A, B {
4696-
virtual void g(); // ill-formed, no diagnostic required
4697-
};
4698-
\end{codeblock}
4699-
\end{example}
4700-
47014658
\indextext{attribute!contracts|)}

source/derived.tex

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -911,9 +911,43 @@
911911
\indextext{function!virtual|)}
912912

913913
\pnum
914-
\begin{note}
915-
For contracts, see \ref{dcl.attr.contract.iface}.
916-
\end{note}
914+
If an overriding function specifies contract conditions\iref{dcl.attr.contract},
915+
it shall specify the same list of contract conditions as
916+
its overridden functions;
917+
no diagnostic is required
918+
if corresponding conditions will always evaluate to the same value.
919+
Otherwise, it is considered to have
920+
the list of contract conditions from one of its overridden functions;
921+
the names in the contract conditions are bound,
922+
and the semantic constraints are checked,
923+
at the point where the contract conditions appear.
924+
Given a virtual function \tcode{f}
925+
with a contract condition that odr-uses \tcode{*this}\iref{basic.def.odr},
926+
the class of which \tcode{f} is a direct member
927+
shall be be an unambiguous and accessible base class of any class
928+
in which \tcode{f} is overridden.
929+
If a function overrides more than one function,
930+
all of the overridden functions shall have
931+
the same list of contract conditions\iref{dcl.attr.contract};
932+
no diagnostic is required
933+
if corresponding conditions will always evaluate to the same value.
934+
\begin{example}
935+
\begin{codeblock}
936+
struct A {
937+
virtual void g() [[expects: x == 0]];
938+
int x = 42;
939+
};
940+
941+
int x = 42;
942+
struct B {
943+
virtual void g() [[expects: x == 0]];
944+
}
945+
946+
struct C : A, B {
947+
virtual void g(); // ill-formed, no diagnostic required
948+
};
949+
\end{codeblock}
950+
\end{example}
917951

918952
\rSec1[class.abstract]{Abstract classes}%
919953

0 commit comments

Comments
 (0)