Files
cppdraft_translate/cppdraft/dcl/contract.md
2025-10-25 03:02:53 +03:00

267 lines
16 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[dcl.contract]
# 9 Declarations [[dcl]](./#dcl)
## 9.4 Function contract specifiers [dcl.contract]
### [9.4.1](#func) General [[dcl.contract.func]](dcl.contract.func)
[function-contract-specifier-seq:](#nt:function-contract-specifier-seq "9.4.1General[dcl.contract.func]")
[*function-contract-specifier*](#nt:function-contract-specifier "9.4.1General[dcl.contract.func]") [*function-contract-specifier-seq*](#nt:function-contract-specifier-seq "9.4.1General[dcl.contract.func]")opt
[function-contract-specifier:](#nt:function-contract-specifier "9.4.1General[dcl.contract.func]")
[*precondition-specifier*](#nt:precondition-specifier "9.4.1General[dcl.contract.func]")
[*postcondition-specifier*](#nt:postcondition-specifier "9.4.1General[dcl.contract.func]")
[precondition-specifier:](#nt:precondition-specifier "9.4.1General[dcl.contract.func]")
pre [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1Attribute syntax and semantics[dcl.attr.grammar]")opt ( [*conditional-expression*](expr.cond#nt:conditional-expression "7.6.16Conditional operator[expr.cond]") )
[postcondition-specifier:](#nt:postcondition-specifier "9.4.1General[dcl.contract.func]")
post [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1Attribute syntax and semantics[dcl.attr.grammar]")opt ( [*result-name-introducer*](#nt:result-name-introducer "9.4.2Referring to the result object[dcl.contract.res]")opt [*conditional-expression*](expr.cond#nt:conditional-expression "7.6.16Conditional operator[expr.cond]") )
[1](#func-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L4613)
A [*function contract assertion*](#def:contract_assertion,function "9.4.1General[dcl.contract.func]") is a contract assertion ([[basic.contract.general]](basic.contract.general "6.11.1General"))
associated with a function[.](#func-1.sentence-1)
A [*precondition-specifier*](#nt:precondition-specifier "9.4.1General[dcl.contract.func]") introduces a [*precondition assertion*](#def:assertion,precondition "9.4.1General[dcl.contract.func]"),
which is a function contract assertion
associated with entering a function[.](#func-1.sentence-2)
A [*postcondition-specifier*](#nt:postcondition-specifier "9.4.1General[dcl.contract.func]") introduces a [*postcondition assertion*](#def:assertion,postcondition "9.4.1General[dcl.contract.func]"),
which is a function contract assertion
associated with exiting a function normally[.](#func-1.sentence-3)
[*Note [1](#func-note-1)*:
A postcondition assertion
is not associated with exiting a function
in any other fashion,
such as via an exception ([[expr.throw]](expr.throw "7.6.18Throwing an exception"))
or via a call to longjmp ([[csetjmp.syn]](csetjmp.syn "17.14.3Header <csetjmp> synopsis"))[.](#func-1.sentence-4)
— *end note*]
[2](#func-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L4635)
The predicate ([[basic.contract.general]](basic.contract.general "6.11.1General"))
of a function contract assertion
is its [*conditional-expression*](expr.cond#nt:conditional-expression "7.6.16Conditional operator[expr.cond]") contextually converted to bool[.](#func-2.sentence-1)
[3](#func-3)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L4641)
Each [*function-contract-specifier*](#nt:function-contract-specifier "9.4.1General[dcl.contract.func]") of a [*function-contract-specifier-seq*](#nt:function-contract-specifier-seq "9.4.1General[dcl.contract.func]") (if any)
of an unspecified first declaration ([[basic.def]](basic.def "6.2Declarations and definitions"))
of a function
introduces a corresponding function contract assertion for that function[.](#func-3.sentence-1)
The optional [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1Attribute syntax and semantics[dcl.attr.grammar]") following pre or post appertains to the introduced contract assertion[.](#func-3.sentence-2)
[*Note [2](#func-note-2)*:
The [*function-contract-specifier-seq*](#nt:function-contract-specifier-seq "9.4.1General[dcl.contract.func]") of a [*lambda-declarator*](expr.prim.lambda.general#nt:lambda-declarator "7.5.6.1General[expr.prim.lambda.general]") applies to the function call operator or operator template
of the corresponding closure type ([[expr.prim.lambda.closure]](expr.prim.lambda.closure "7.5.6.2Closure types"))[.](#func-3.sentence-3)
— *end note*]
[4](#func-4)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L4657)
A declaration D of a function or function template *f* that is not a first declaration shall have either
no [*function-contract-specifier-seq*](#nt:function-contract-specifier-seq "9.4.1General[dcl.contract.func]") or the same [*function-contract-specifier-seq*](#nt:function-contract-specifier-seq "9.4.1General[dcl.contract.func]") (see below)
as any first declaration F reachable from D[.](#func-4.sentence-1)
If D and F are
in different translation units,
a diagnostic is required only if D is attached to a named module[.](#func-4.sentence-2)
If a declaration F1 is a
first declaration of f in one translation unit and
a declaration F2 is a
first declaration of f in another translation unit,F1 and F2 shall specify the same[*function-contract-specifier-seq*](#nt:function-contract-specifier-seq "9.4.1General[dcl.contract.func]"), no diagnostic required[.](#func-4.sentence-3)
[5](#func-5)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L4675)
A [*function-contract-specifier-seq*](#nt:function-contract-specifier-seq "9.4.1General[dcl.contract.func]") S1 is the same as
a [*function-contract-specifier-seq*](#nt:function-contract-specifier-seq "9.4.1General[dcl.contract.func]") S2 if S1 and S2 consist of
the same [*function-contract-specifier*](#nt:function-contract-specifier "9.4.1General[dcl.contract.func]")*s* in the same order[.](#func-5.sentence-1)
A [*function-contract-specifier*](#nt:function-contract-specifier "9.4.1General[dcl.contract.func]") C1 on a function declaration D1 is
the same as
a [*function-contract-specifier*](#nt:function-contract-specifier "9.4.1General[dcl.contract.func]") C2 on a function declaration D2 if
- [(5.1)](#func-5.1)
their predicates P1 and P2 would
satisfy the one-definition rule ([[basic.def.odr]](basic.def.odr "6.3One-definition rule"))
if placed in function definitions on
the declarations D1 and D2, respectively, except for
* [(5.1.1)](#func-5.1.1)
renaming of the parameters of *f*,
* [(5.1.2)](#func-5.1.2)
renaming of template parameters of
a template enclosing , and
* [(5.1.3)](#func-5.1.3)
renaming of the result binding ([[dcl.contract.res]](#res "9.4.2Referring to the result object")), if any,
and,
if D1 and D2 are in different translation units,
corresponding entities defined within each predicate
behave as if there is a single entity with a single definition, and
- [(5.2)](#func-5.2)
both C1 and C2 specify a [*result-name-introducer*](#nt:result-name-introducer "9.4.2Referring to the result object[dcl.contract.res]") or neither do[.](#func-5.sentence-2)
If this condition is not met
solely due to the comparison of two [*lambda-expression*](expr.prim.lambda.general#nt:lambda-expression "7.5.6.1General[expr.prim.lambda.general]")*s* that are contained within P1 and P2,
no diagnostic is required[.](#func-5.sentence-3)
[*Note [3](#func-note-3)*:
Equivalent[*function-contract-specifier-seq*](#nt:function-contract-specifier-seq "9.4.1General[dcl.contract.func]")*s* apply to all uses and definitions
of a function across all translation units[.](#func-5.sentence-4)
— *end note*]
[*Example [1](#func-example-1)*: bool b1, b2;
void f() pre (b1) pre ([]{ return b2; }());void f(); // OK, [*function-contract-specifier*](#nt:function-contract-specifier "9.4.1General[dcl.contract.func]")*s* omittedvoid f() pre (b1) pre ([]{ return b2; }()); // error: closures have different types.void f() pre (b1); // error: [*function-contract-specifier*](#nt:function-contract-specifier "9.4.1General[dcl.contract.func]")*s* only partially repeatedint g() post(r : b1);int g() post(b1); // error: mismatched [*result-name-introducer*](#nt:result-name-introducer "9.4.2Referring to the result object[dcl.contract.res]") presencenamespace N {void h() pre (b1); bool b1; void h() pre (b1); // error: [*function-contract-specifier*](#nt:function-contract-specifier "9.4.1General[dcl.contract.func]")*s* differ according to// the one-definition rule ([[basic.def.odr]](basic.def.odr "6.3One-definition rule")).} — *end example*]
[6](#func-6)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L4745)
A virtual function ([[class.virtual]](class.virtual "11.7.3Virtual functions")),
a deleted function ([[dcl.fct.def.delete]](dcl.fct.def.delete "9.6.3Deleted definitions")),
or a function defaulted on its first declaration ([[dcl.fct.def.default]](dcl.fct.def.default "9.6.2Explicitly-defaulted functions"))
shall not have a [*function-contract-specifier-seq*](#nt:function-contract-specifier-seq "9.4.1General[dcl.contract.func]")[.](#func-6.sentence-1)
[7](#func-7)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L4751)
If the predicate of a postcondition assertion
of a function *f* odr-uses ([[basic.def.odr]](basic.def.odr "6.3One-definition rule"))
a non-reference parameter of *f*,
that parameter
and the corresponding parameter on all declarations of *f* shall have const type[.](#func-7.sentence-1)
[*Note [4](#func-note-4)*:
This requirement applies
even to declarations that do not specify the [*postcondition-specifier*](#nt:postcondition-specifier "9.4.1General[dcl.contract.func]")[.](#func-7.sentence-2)
Parameters with array or function type
will decay to non-const types
even if a const qualifier is present[.](#func-7.sentence-3)
[*Example [2](#func-example-2)*: int f(const int i[10]) post(r : r == i[0]); // error: i has type const int * (not int* const). — *end example*]
— *end note*]
[8](#func-8)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L4773)
[*Note [5](#func-note-5)*:
The function contract assertions of a function
are evaluated even when invoked indirectly,
such as through a pointer to function or a pointer to member function[.](#func-8.sentence-1)
A pointer to function,
pointer to member function,
or function type alias
cannot have a [*function-contract-specifier-seq*](#nt:function-contract-specifier-seq "9.4.1General[dcl.contract.func]") associated directly with it[.](#func-8.sentence-2)
— *end note*]
[9](#func-9)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L4785)
The function contract assertions of a function
are considered to be [*needed*](#def:needed,function_contract_assertion "9.4.1General[dcl.contract.func]") ([[temp.inst]](temp.inst "13.9.2Implicit instantiation")) when
- [(9.1)](#func-9.1)
the function is odr-used ([[basic.def.odr]](basic.def.odr "6.3One-definition rule")) or
- [(9.2)](#func-9.2)
the function is defined[.](#func-9.sentence-1)
[*Note [6](#func-note-6)*:
Overload resolution does not consider[*function-contract-specifier*](#nt:function-contract-specifier "9.4.1General[dcl.contract.func]")*s* ([[temp.deduct]](temp.deduct "13.10.3Template argument deduction"), [[temp.inst]](temp.inst "13.9.2Implicit instantiation"))[.](#func-9.sentence-2)
[*Example [3](#func-example-3)*: template <typename T> void f(T t) pre( t == "" );template <typename T> void f(T&& t);void g(){ f(5); // error: ambiguous} — *end example*]
— *end note*]
### [9.4.2](#res) Referring to the result object [[dcl.contract.res]](dcl.contract.res)
[attributed-identifier:](#nt:attributed-identifier "9.4.2Referring to the result object[dcl.contract.res]")
[*identifier*](lex.name#nt:identifier "5.11Identifiers[lex.name]") [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1Attribute syntax and semantics[dcl.attr.grammar]")opt
[result-name-introducer:](#nt:result-name-introducer "9.4.2Referring to the result object[dcl.contract.res]")
[*attributed-identifier*](#nt:attributed-identifier "9.4.2Referring to the result object[dcl.contract.res]") :
[1](#res-1)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L4822)
The [*result-name-introducer*](#nt:result-name-introducer "9.4.2Referring to the result object[dcl.contract.res]") of a [*postcondition-specifier*](#nt:postcondition-specifier "9.4.1General[dcl.contract.func]") is a declaration[.](#res-1.sentence-1)
The [*result-name-introducer*](#nt:result-name-introducer "9.4.2Referring to the result object[dcl.contract.res]") introduces the [*identifier*](lex.name#nt:identifier "5.11Identifiers[lex.name]") as the name of a [*result binding*](#def:result_binding "9.4.2Referring to the result object[dcl.contract.res]") of the associated function[.](#res-1.sentence-2)
If a postcondition assertion has a [*result-name-introducer*](#nt:result-name-introducer "9.4.2Referring to the result object[dcl.contract.res]") and the return type of the function is cv void,
the program is ill-formed[.](#res-1.sentence-3)
A result binding denotes
the object or reference returned by
invocation of that function[.](#res-1.sentence-4)
The type of a result binding
is the return type of its associated function[.](#res-1.sentence-5)
The optional [*attribute-specifier-seq*](dcl.attr.grammar#nt:attribute-specifier-seq "9.13.1Attribute syntax and semantics[dcl.attr.grammar]") of the [*attributed-identifier*](#nt:attributed-identifier "9.4.2Referring to the result object[dcl.contract.res]") in the [*result-name-introducer*](#nt:result-name-introducer "9.4.2Referring to the result object[dcl.contract.res]") appertains to the result binding so introduced[.](#res-1.sentence-6)
[*Note [1](#res-note-1)*:
An [*id-expression*](expr.prim.id.general#nt:id-expression "7.5.5.1General[expr.prim.id.general]") that names a result binding is a const lvalue ([[expr.prim.id.unqual]](expr.prim.id.unqual "7.5.5.2Unqualified names"))[.](#res-1.sentence-7)
— *end note*]
[*Example [1](#res-example-1)*: int f() post(r : r == 1){return 1;}int i = f(); // Postcondition check succeeds. — *end example*]
[*Example [2](#res-example-2)*: struct A {};struct B { B() {} B(const B&) {}};
template <typename T> T f(T* const ptr) post(r: &r == ptr){return {};}int main() { A a = f(&a); // The postcondition check can fail if the implementation introduces// a temporary for the return value ([[class.temporary]](class.temporary "6.8.7Temporary objects")). B b = f(&b); // The postcondition check succeeds, no temporary is introduced.} — *end example*]
[2](#res-2)
[#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/declarations.tex#L4882)
When the declared return type
of a non-templated function
contains a placeholder type,
a [*postcondition-specifier*](#nt:postcondition-specifier "9.4.1General[dcl.contract.func]") with a [*result-name-introducer*](#nt:result-name-introducer "9.4.2Referring to the result object[dcl.contract.res]") shall be present only on a definition[.](#res-2.sentence-1)
[*Example [3](#res-example-3)*: auto g(auto&) post (r: r >= 0); // OK, g is a template.auto h() post (r: r >= 0); // error: cannot name the return valueauto k() post (r: r >= 0) // OK{return 0;} — *end example*]