Repository navigation
E14: contracts across the files of one run, and trust that stays on the definition - #98
Merged
Merged
Conversation
…ps, and name an unmeasured loop beside a failure.
… proved by unrolling, and beside an unmeasured loop.
…their verdicts rely on so that each is a whole run's verdict.
…se that is executable.
…h its counterexample and backend.
…solving each after the first past the earlier failures.
…firm a failure after a loop past the checks that fail before it.
…sing the earlier failures reaches.
… once in confirmation_invariants.cpp.
…ver finds at once.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Real code declares a function with its contract in a header and defines it in one
.cppfile. Before this PR, two things went wrong with that layout:Unresolved [callee.contract], even when one run verified both files.[[cppverify::trusted]]on the declaration, also stopped the verification of the definition, which inherits the mark through Clang's attribute inheritance. A wrong body was then never checked.Now one run over several files settles such a contract. This is R26 from the plan:
With
return 100;both functions verify, and the warning thatclamp100has no definition is not printed.On the base (#97),
scaledisUnresolvedbecause clamp100 has "no definition", whether or notclamp100is right. With the header's declaration marked trusted,mathx.cppreportsTrusted: clamp100and the bug goes unchecked.Stacked on #97. This is plan item E14, its first two steps: decision Q13, taken as recommended, (a); and one invocation over several files. Separate compilation with a link check, the third step, is left for later.
Design
Trust stays on the definition (Q13). A function with a definition is trusted only when the definition carries the mark itself (
!Attr->isInherited()). A declaration's mark means that callers which see no definition assume the contract. A spec still rejects the mark on any of its declarations.One run over several files. With more than one file, the driver creates a
CrossFileRun. Each file is then handled as follows:Verifier::Externals), instead of leaving its callers unresolved at once.ExternalOf).DefinedContracts).renderReport). Each line is rendered as verified. A proof that rests on external contracts is also rendered asdemotemakes it, with a placeholder for the contracts. Both variants are counted for the summary.Settlement. Once every file is verified,
CrossFileRun::finishestablishes contracts by a least fixpoint, starting from none, as within a file. A contract is established once every definition of it is established in its file, and the external contracts that rests on are. It then prints each file's lines in the order given, with the demoted form where a contract a proof rests on is not established. The message says which of three cases applies:The settlement also drops the "no definition" warning of a contract some file defines, and the findings of a demoted proof (except those of the entry state, as within a file). Files with a demoted proof fail the exit status.
Matching. A declaration matches a definition by the function's identity (its mangled name) and its contract as written, each clause printed by Clang (
ASTConverter::contractText). A declaration that states another contract (an ODR violation) is not matched, which keeps it from borrowing a proof of a different claim.Unchanged. A file verified alone behaves exactly as before. A trusted declaration stays an assumption, flagged with
[trusts=...]. Lean runs and--list-functionsdo not settle across files.Tests
suite/trusted_declarations.cpp(new): a header-style trusted declaration whose definition in the same file breaks the contract (now a failure, and its callerUnresolved), a trusted definition (stillTrusted), a trusted declaration without a definition (assumed,[trusts=above]), and a spec with a trusted declaration (an error).suite/contracts_across_files.test(new, inputs inInputs/across/):Unresolved, transitively, and the definition's failure);Each mutant below, applied alone, makes one of the two tests fail:
X6 is the soundness check of the matching. Under it, a declaration that promises
result <= 50borrows a proof ofresult <= 100, and its caller verifies.Docs
Checked
clang/test/Verifyon this branch: 487 passed, 1 unsupported (darwin only), no failure, includingdocs_examples.testanddocs_coverage.testwith the new section.