Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
95 commits
Select commit Hold shift + click to select a range
747ba38
verify: Say that archives keep a logical function's measures and wher…
SwayamInSync Oct 23, 2026
d4592ba
verify: Validate a logical function's termination measures like its d…
SwayamInSync Oct 23, 2026
2ce8c54
verify: Keep the functions a termination measure applies when canonic…
SwayamInSync Oct 23, 2026
6a7d0a6
verify: Make obligation archives schema 3.
SwayamInSync Oct 23, 2026
d67c76f
verify: Archive termination measures and where each assumption of a g…
SwayamInSync Oct 23, 2026
4196eef
verify: Mark the unwinding goals of a Lean project.
SwayamInSync Oct 23, 2026
760896f
verify: State the bound of a bounded module with its Lean goals.
SwayamInSync Oct 23, 2026
ee37f71
verify: Declare the replay of archived modules into a Lean project.
SwayamInSync Oct 23, 2026
818ce9a
verify: Write Lean projects through one LeanProject, from source or f…
SwayamInSync Oct 23, 2026
4c0bc6a
verify: Replay archives into Lean projects, and bounded archives into…
SwayamInSync Oct 23, 2026
93f2c2c
test: Read schema 3 archives, and write schema 2 ones, in the archive…
SwayamInSync Oct 23, 2026
c474886
test: Expect schema 3, read schema 2, and reject a measure with a fre…
SwayamInSync Oct 23, 2026
f799055
test: Expect schema 3 in the obligation IR dump.
SwayamInSync Oct 23, 2026
b6e2857
test: Add the program of the Lean replay test.
SwayamInSync Oct 23, 2026
b5b3b06
test: Add the loops of the Lean replay test.
SwayamInSync Oct 23, 2026
7df524a
test: Check that an archive replays into a Lean project as its source…
SwayamInSync Oct 23, 2026
b255c43
docs: Explain archives in Lean projects in chapter 17.
SwayamInSync Oct 23, 2026
8ce4ce2
docs: Say how an archive replays into a Lean project.
SwayamInSync Oct 23, 2026
cdeb7df
docs: Note Lean projects from archives and schema 3 in the release no…
SwayamInSync Oct 23, 2026
76270a9
docs: Describe Lean replay and schema 3 in the design.
SwayamInSync Oct 23, 2026
cb86df1
docs: Describe LeanProject, Lean replay, and schema 3 in the architec…
SwayamInSync Oct 23, 2026
87dc023
docs: Say that archives keep where each assumption of a goal comes fr…
SwayamInSync Oct 23, 2026
5f55b5a
verify: Let a certified counterexample carry the values of its goal's…
SwayamInSync Oct 23, 2026
742e6c7
verify: Declare the assignment of a certified counterexample.
SwayamInSync Oct 23, 2026
288e9a4
verify: Read the assignment of a certified counterexample from its ca…
SwayamInSync Oct 23, 2026
aeb2182
verify: Keep the assignment of each counterexample the Z3 adapter cer…
SwayamInSync Oct 23, 2026
ce3dc2b
verify: Declare the Lean refutation of a counterexample.
SwayamInSync Oct 23, 2026
34415e8
verify: Export a counterexample as a Lean refutation, and decide boun…
SwayamInSync Oct 23, 2026
0ce1031
verify: Add the cppverify_refute tactic.
SwayamInSync Oct 23, 2026
0a057ff
verify: Check refutation entries against the negation of their goals.
SwayamInSync Oct 23, 2026
e31d645
verify: Confirm the counterexamples of a fallback project in Lean.
SwayamInSync Oct 23, 2026
2706a6e
test: Add the program of the Lean refutation test.
SwayamInSync Oct 23, 2026
481b3c8
test: Add the refutations of the Lean refutation test that are bounde…
SwayamInSync Oct 23, 2026
8143117
test: Add the instances the refutation tactic must not refute.
SwayamInSync Oct 23, 2026
feac3c4
test: Check that counterexamples are confirmed in Lean, or left with …
SwayamInSync Oct 23, 2026
e6cc4da
test: Add the proof of the one fidelity matrix goal cppverify_auto le…
SwayamInSync Oct 23, 2026
97c7129
test: Require decisive Lean verdicts in the backend fidelity gate.
SwayamInSync Oct 23, 2026
bda0be4
test: Check the decisive Lean row of the backend fidelity gate.
SwayamInSync Oct 23, 2026
4e72ac8
docs: Lower a documentation example without its Lean output options.
SwayamInSync Oct 23, 2026
7ae3671
docs: Explain counterexamples in Lean in chapter 17.
SwayamInSync Oct 23, 2026
823ae1f
docs: Say that a fallback project refutes certified counterexamples.
SwayamInSync Oct 23, 2026
88cd63a
docs: Note counterexamples confirmed in Lean in the release notes.
SwayamInSync Oct 23, 2026
a957a73
docs: Describe Lean refutations in the design.
SwayamInSync Oct 23, 2026
90189a8
docs: Describe Lean refutations and the gate's Lean row in the archit…
SwayamInSync Oct 23, 2026
b41eba8
verify: Mark a function that uses a construct the verifier does not r…
SwayamInSync Oct 24, 2026
8966deb
verify: Copy the unsupported-construct mark with a function.
SwayamInSync Oct 24, 2026
d2c2979
verify: Keep the unsupported-construct mark through loop unrolling.
SwayamInSync Oct 24, 2026
7a44559
verify: Report a malformed inductive predicate with the predicate.
SwayamInSync Oct 24, 2026
219e435
verify: Name the predicate of each inductive predicate error.
SwayamInSync Oct 24, 2026
036a376
verify: Record the function and part of it each conversion error belo…
SwayamInSync Oct 24, 2026
a027243
verify: Keep what others may rely on of a function the verifier canno…
SwayamInSync Oct 24, 2026
5de19af
verify: Verify every function but those using a construct the verifie…
SwayamInSync Oct 24, 2026
f96eed0
test: Check the verdict that an unsupported construct's record carries.
SwayamInSync Oct 24, 2026
80eb0e4
test: Add the program of the per-function errors test.
SwayamInSync Oct 24, 2026
10dba84
test: Check that an unsupported construct costs its function alone.
SwayamInSync Oct 24, 2026
a24894d
docs: Say that an unsupported construct costs its function alone.
SwayamInSync Oct 24, 2026
94c24f4
docs: Describe failing closed per function in the limitations.
SwayamInSync Oct 24, 2026
6898ea4
docs: Extend construct.unsupported to whole functions in chapter 16.
SwayamInSync Oct 24, 2026
e176567
docs: Note that an unsupported construct costs its function alone in …
SwayamInSync Oct 24, 2026
7495172
docs: Describe per-function unsupported constructs in the design.
SwayamInSync Oct 24, 2026
faa6c01
docs: Describe per-function conversion errors in the architecture.
SwayamInSync Oct 24, 2026
e6bf536
verify: Keep only scalar reference parameters as footprints of one cell.
SwayamInSync Oct 24, 2026
69c1fcc
verify: Clone a function's scalar reference parameters.
SwayamInSync Oct 24, 2026
b504ed4
verify: Keep a function's scalar reference parameters through loop un…
SwayamInSync Oct 24, 2026
49ecde6
verify: Frame a record reference's footprint as its object, and name …
SwayamInSync Oct 24, 2026
7825fcb
verify: Declare the places and pointers reached through references to…
SwayamInSync Oct 24, 2026
959018e
verify: Verify records through references, as pointers never null or …
SwayamInSync Oct 24, 2026
6b05b73
test: Check records through references and members named whole in mod…
SwayamInSync Oct 24, 2026
1f3fedf
test: Stop expecting a reference to a record to be rejected.
SwayamInSync Oct 24, 2026
d906f99
docs: Describe records through references, with a checked example.
SwayamInSync Oct 24, 2026
a8b47d5
docs: Extend records and frames to references to records in chapter 14.
SwayamInSync Oct 24, 2026
a430f47
docs: List references to records as supported in the limitations.
SwayamInSync Oct 24, 2026
af65377
docs: Mention references to records on the front page.
SwayamInSync Oct 24, 2026
34b3ece
docs: Note records through references and members named whole in the …
SwayamInSync Oct 24, 2026
02e7fa7
docs: Describe records through references in the design.
SwayamInSync Oct 24, 2026
63b2b98
docs: Describe records through references in the architecture.
SwayamInSync Oct 24, 2026
17b3c68
verify: Decide a quantifier over a range of integers in Lean only for…
SwayamInSync Oct 24, 2026
0776e1d
test: Add a refutation over a thousand integers to the budget input.
SwayamInSync Oct 24, 2026
9f63ff7
test: Check that a quantifier over a thousand integers is refuted in …
SwayamInSync Oct 24, 2026
d5d21db
test: Check that refuting a quantifier over a billion integers stays …
SwayamInSync Oct 24, 2026
824cbf9
docs: Describe the range bound of the Lean prelude's quantifiers in t…
SwayamInSync Oct 24, 2026
b8fec4f
docs: Bound the Lean prelude's quantifiers to 4096 integers in the de…
SwayamInSync Oct 24, 2026
30fae89
docs: Bound the Lean prelude's quantifiers to 4096 integers in chapte…
SwayamInSync Oct 24, 2026
c26a4ed
docs: Bound the Lean prelude's quantifiers to 4096 integers in the re…
SwayamInSync Oct 24, 2026
c7f50c4
Merge branch 'fix/lean-refutations' into fix/per-function-errors.
SwayamInSync Oct 24, 2026
89d8e14
Merge branch 'fix/per-function-errors' into fix/record-references.
SwayamInSync Oct 24, 2026
51cde57
verify: Test the result of Lean certification once, so a failure is a…
SwayamInSync Oct 24, 2026
a3fa00e
test: Check that replaying an archive reports a failed Lean certifica…
SwayamInSync Oct 24, 2026
d25912c
Merge branch 'fix/lean-refutations' into fix/per-function-errors.
SwayamInSync Oct 24, 2026
a504d1c
Merge branch 'fix/per-function-errors' into fix/record-references.
SwayamInSync Oct 24, 2026
76aa3b9
verify: Mangle a constructor or destructor as its complete-object var…
SwayamInSync Oct 24, 2026
abcbf5d
Merge branch 'fix/per-function-errors' into fix/record-references.
SwayamInSync Oct 24, 2026
6e1b3f8
verify: Name a template or member function only when it has contracts…
SwayamInSync Oct 24, 2026
7412ac9
test: Check that a run under the Microsoft ABI mangles no template.
SwayamInSync Oct 24, 2026
0959fdd
Merge branch 'fix/per-function-errors' into fix/record-references.
SwayamInSync Oct 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions clang/lib/Verify/Backend/Certify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4150,6 +4150,22 @@ void sourceVariables(const LogicExpr *Expr, std::set<std::string> &Bound,
}
} // namespace

std::shared_ptr<const CounterexampleAssignment>
verify::counterexampleAssignment(const Obligation &Item,
CandidateModel &Model) {
std::vector<std::pair<std::string, LogicSort>> Variables;
std::set<std::string> Bound;
sourceVariables(Item.Goal.get(), Bound, Variables);
auto Assignment = std::make_shared<CounterexampleAssignment>();
for (const auto &[Name, Sort] : Variables) {
std::optional<LogicValue> Given = Model.constant(Name, Sort);
if (!Given)
return nullptr;
Assignment->Values.emplace(Name, std::move(*Given));
}
return Assignment;
}

std::vector<VerifyModelValue>
verify::candidateValues(const ObligationModule &Module, const LogicExpr &Query,
CandidateModel &Model) {
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/Verify/Backend/Certify.h
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,18 @@ std::optional<LogicValue> evaluateTerm(const ObligationModule &Module,
const CertifyLimits &Limits = {},
std::string *Failure = nullptr);

/// The values a certified counterexample gives the free variables of the goal
/// of the obligation it fails, by name: what a refutation of that goal
/// applies it to.
struct CounterexampleAssignment {
std::map<std::string, LogicValue> Values;
};

/// The assignment \p Model gives the free variables of \p Item's goal, or
/// null when it gives one no value.
std::shared_ptr<const CounterexampleAssignment>
counterexampleAssignment(const Obligation &Item, CandidateModel &Model);

/// The source variables of \p Query with the values \p Model gives them, as
/// a counterexample shows them; no value where the model gives none.
std::vector<VerifyModelValue> candidateValues(const ObligationModule &Module,
Expand Down
173 changes: 172 additions & 1 deletion clang/lib/Verify/Backend/LeanBackend.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
//===--- LeanBackend.cpp --------------------------------------------------===//
#include "LeanBackend.h"
#include "Certify.h"
#include "ObligationSerialization.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
Expand Down Expand Up @@ -1293,6 +1294,41 @@ static std::string leanSpecDefinition(const ObligationModule &Module,
return Failed ? "" : Text;
}

// A quantifier over a range of integers, as a goal states one, is decided by
// trying each integer of the range, as core Lean decides one over a range of
// naturals, when the range has at most 4096 integers, as many as the
// certifier expands (CertifyLimits::DirectExpansion). Each integer is a level
// of recursion whose memory heartbeats do not count: under the generated
// files' recursion depth a range of 64000 took 58 GB before failing, and one
// of 4000 already spent a step's heartbeats. A larger range has the classical
// instance, which decide cannot evaluate.
static constexpr llvm::StringLiteral LeanBoundedQuantifierPrelude =
R"lean(instance cppIntBallDecidable (lo hi : Int) (p : Int → Prop) [DecidablePred p] :
Decidable (∀ x : Int, lo ≤ x ∧ x < hi → p x) :=
if (hi - lo).toNat ≤ 4096 then
decidable_of_iff (∀ k : Nat, k < (hi - lo).toNat → p (lo + k)) (by
constructor
· intro h x hx
have := h (x - lo).toNat (by omega)
rwa [show lo + ((x - lo).toNat : Int) = x by omega] at this
· intro h k hk
exact h _ ⟨by omega, by omega⟩)
else Classical.propDecidable _

instance cppIntBexDecidable (lo hi : Int) (p : Int → Prop) [DecidablePred p] :
Decidable (∃ x : Int, lo ≤ x ∧ x < hi ∧ p x) :=
if (hi - lo).toNat ≤ 4096 then
decidable_of_iff (∃ k : Nat, k < (hi - lo).toNat ∧ p (lo + k)) (by
constructor
· rintro ⟨k, hk, hp⟩
exact ⟨lo + k, by omega, by omega, hp⟩
· rintro ⟨x, h1, h2, hp⟩
refine ⟨(x - lo).toNat, by omega, ?_⟩
rwa [show lo + ((x - lo).toNat : Int) = x by omega])
else Classical.propDecidable _

)lean";

static void emitLeanFunctionDeclarations(
const ObligationModule &Module, llvm::raw_ostream &OS,
std::set<std::string> &EmittedFunctions,
Expand Down Expand Up @@ -1680,6 +1716,7 @@ void verify::emitLeanPrelude(llvm::raw_ostream &OS, bool Project) {
OS << " if (x < 0) ≠ (y < 0) then -q else q\n";
OS << "def cppIntRem (x y : Int) : Int :=\n";
OS << " if y = 0 then x else x - cppIntDiv x y * y\n\n";
OS << LeanBoundedQuantifierPrelude;
OS << LeanCollectionPrelude;
OS << "/- Proves that an application in a spec's definition lowers its "
"measure. -/\n";
Expand All @@ -1704,6 +1741,77 @@ void verify::emitLeanPrelude(llvm::raw_ostream &OS, bool Project) {
}
}

// A piecewise-constant function of the integers as a Lean term: the cell
// of each address, from the run it lies in.
static void printLeanRuns(const HeapValue &Runs, llvm::StringRef Before,
llvm::StringRef After, llvm::raw_ostream &OS) {
OS << "(fun (a : Int) => ";
for (auto It = Runs.Breaks.rbegin(); It != Runs.Breaks.rend(); ++It)
OS << "if a ≥ (" << It->first.toDecimal() << " : Int) then " << Before
<< It->second.toDecimal() << After << " else ";
OS << Before << Runs.Default.toDecimal() << After << ")";
}

// A model's value as a Lean term of its sort; false when it has none.
static bool printLeanValue(const LogicValue &Value, const LogicSort &Sort,
llvm::raw_ostream &OS) {
switch (Sort.Kind) {
case LogicSortKind::Bool:
if (Value.K != LogicValue::Kind::Bool)
return false;
OS << (Value.Truth ? "True" : "False");
return true;
case LogicSortKind::MathematicalInteger:
case LogicSortKind::Pointer:
if (Value.K != LogicValue::Kind::Integer)
return false;
OS << "(" << Value.Integer.toDecimal() << " : Int)";
return true;
case LogicSortKind::BitVector:
if (Value.K != LogicValue::Kind::Integer)
return false;
OS << "(BitVec.ofInt " << Sort.BitWidth << " (" << Value.Integer.toDecimal()
<< "))";
return true;
case LogicSortKind::Heap:
if (Value.K != LogicValue::Kind::Heap || !Value.Heap)
return false;
printLeanRuns(*Value.Heap, "(", " : Int)", OS);
return true;
case LogicSortKind::Seq:
if (Value.K != LogicValue::Kind::Seq || !Value.Elements)
return false;
OS << "([";
for (size_t I = 0; I != Value.Elements->size(); ++I)
OS << (I ? ", " : "") << "(" << (*Value.Elements)[I].toDecimal()
<< " : Int)";
OS << "] : List Int)";
return true;
case LogicSortKind::Set:
if (Value.K != LogicValue::Kind::Set || !Value.Heap)
return false;
printLeanRuns(*Value.Heap, "decide ((", " : Int) ≠ 0)", OS);
return true;
case LogicSortKind::Multiset:
if (Value.K != LogicValue::Kind::Multiset || !Value.Heap)
return false;
printLeanRuns(*Value.Heap, "((", " : Int).toNat)", OS);
return true;
case LogicSortKind::Map:
if (Value.K != LogicValue::Kind::Map || !Value.Heap || !Value.Values)
return false;
OS << "(fun (k : Int) => if ";
printLeanRuns(*Value.Heap, "(", " : Int)", OS);
OS << " k ≠ 0 then some (";
printLeanRuns(*Value.Values, "(", " : Int)", OS);
OS << " k) else none)";
return true;
case LogicSortKind::Invalid:
return false;
}
return false;
}

VerifyResult verify::exportLeanScratchPad(
const ObligationModule &Module, llvm::raw_ostream &OS, bool EmitPreamble,
std::set<std::string> &EmittedFunctions,
Expand Down Expand Up @@ -1757,7 +1865,13 @@ VerifyResult verify::exportLeanScratchPad(
printLeanCommentText(Module.FunctionName, OS);
OS << " -/\n";
OS << "/- required logic: " << formatLogicFeatures(Module.RequiredFeatures)
<< " -/\n\n";
<< " -/\n";
if (Module.BMCTransform)
OS << "/- bound: " << Module.BMCTransform->UnrollBound
<< " loop iterations, by unrolling: these goals speak only of the\n"
" executions within them, and an unwinding goal says that every "
"loop\n ends within them -/\n";
OS << "\n";

std::string TheoremName =
"cppverify_" +
Expand Down Expand Up @@ -1805,6 +1919,7 @@ VerifyResult verify::exportLeanScratchPad(
Goal.LegacyName = encodeLeanName(ObligationName + "_goal");
Goal.LegacyBodyPrefix = LegacyBodyPrefix;
Goal.Exported = Selected;
Goal.Unwinding = Item.Kind == ObligationKind::Unwinding;
if (!Selected) {
ProjectGoals->push_back(std::move(Goal));
continue;
Expand Down Expand Up @@ -1847,4 +1962,60 @@ VerifyResult verify::exportLeanScratchPad(
Result.Message = ProjectGoals ? "editable Lean project obligation export"
: "unchecked Lean obligation export";
return Result;
}

std::optional<LeanRefutation> verify::exportLeanRefutation(
const ObligationModule &Module, const Obligation &Item,
const CounterexampleAssignment &Assignment,
std::map<std::string, LeanSpecDeclaration> &Specs, std::string &Why) {
// The goal, its bodies, and its specs as its project states them.
std::string Goals;
llvm::raw_string_ostream GoalsOS(Goals);
std::set<std::string> Functions, Theorems;
std::vector<LeanProjectGoal> Stated;
const std::set<std::string> Selection = {Item.Id};
VerifyResult Exported = exportLeanScratchPad(
Module, GoalsOS, /*EmitPreamble=*/false, Functions, Theorems,
/*ModuleIndex=*/1, &Stated, &Selection, &Specs);
auto Goal = llvm::find_if(
Stated, [](const LeanProjectGoal &Goal) { return Goal.Exported; });
if (Exported.Status != VerifyStatus::Exported || Goal == Stated.end()) {
Why = Exported.Message.empty() ? "the goal has no Lean statement"
: Exported.Message;
return std::nullopt;
}

// The goal applied to the values of its variables, in the order it binds
// them; the definition instances it states then hold by evaluation.
std::string Application;
llvm::raw_string_ostream ApplicationOS(Application);
std::map<std::string, LogicSort> Variables;
collectLeanVariables(Item.Goal.get(), {}, Variables);
for (const auto &[Name, Sort] : Variables) {
auto Value = Assignment.Values.find(Name);
ApplicationOS << "\n ";
if (Value == Assignment.Values.end() ||
!printLeanValue(Value->second, Sort, ApplicationOS)) {
Why = "the counterexample gives " + Name + " no value Lean can state";
return std::nullopt;
}
}

LeanRefutation Refutation;
Refutation.Group = Goal->Group;
Refutation.Goal = Goal->Name;
Refutation.StableId = Goal->StableId;
llvm::raw_string_ostream OS(Refutation.Text);
OS << "import CppVerify.Specs\nimport CppVerify.Auto\n\n"
<< "noncomputable section\n\nset_option maxRecDepth 100000\n"
<< "set_option linter.unusedVariables false\n\n"
<< "section Goal\n\nset_option maxHeartbeats 0\n\n"
<< "attribute [local instance] cppVerifyPropDecidable\n\n"
<< Goals << "end Goal\n\n"
<< "/- The goal is false at the counterexample of "
<< (Item.StableId.empty() ? Item.Id : Item.StableId) << ". -/\n"
<< "theorem " << Goal->Name << "_refuted : ¬ " << Goal->Name
<< " := by\n intro h\n have h₁ := h" << Application
<< "\n cppverify_refute h₁\n";
return Refutation;
}
23 changes: 23 additions & 0 deletions clang/lib/Verify/Backend/LeanBackend.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ struct LeanProjectGoal {
/// False for an obligation of an exported function that a selection left
/// to the solver: its goal is known, but has no definition or proof file.
bool Exported = true;
/// An unwinding goal of a bounded module: that its loops end within the
/// bound.
bool Unwinding = false;
};

/// The group of a module's goals in a project: its function's directory.
Expand Down Expand Up @@ -78,6 +81,26 @@ VerifyResult exportLeanScratchPad(
const std::set<std::string> *Selection = nullptr,
std::map<std::string, LeanSpecDeclaration> *Specs = nullptr);

/// A certified counterexample shown in Lean: a module of the project's
/// group directory, Refutations/<Group>/<Goal>.lean, that states the goal as
/// the project would and proves `<Goal>_refuted : ¬ <Goal>` at the values.
struct LeanRefutation {
std::string Group;
std::string Goal;
std::string StableId;
std::string Text;
};

/// The refutation of Item's goal at Assignment, the values a certified
/// counterexample gives its variables. Specs receives the specs it applies,
/// as a project's export does. None, with Why, when a value has no Lean
/// form.
std::optional<LeanRefutation>
exportLeanRefutation(const ObligationModule &Module, const Obligation &Item,
const CounterexampleAssignment &Assignment,
std::map<std::string, LeanSpecDeclaration> &Specs,
std::string &Why);

class LeanVerifyBackend : public VerifyBackend {
llvm::raw_ostream *Out = nullptr;
LeanProjectModules *Modules = nullptr;
Expand Down
20 changes: 20 additions & 0 deletions clang/lib/Verify/Backend/Obligation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2578,6 +2578,26 @@ verify::validateObligationModule(const ObligationModule &M) {
ValidationError.c_str());
collectRequiredFeatures(Definition.get(), RequiredFeatures);
}
// A measure only chooses an induction or Lean's termination argument,
// so it adds no feature; it must still be an integer over the
// parameters.
for (const auto &Measure : Declaration.Decreases) {
if (!validateLogicExpr(Measure.get(), ValidationError))
return llvm::createStringError(llvm::inconvertibleErrorCode(), "%s",
ValidationError.c_str());
if (Measure->Sort.Kind != LogicSortKind::MathematicalInteger &&
Measure->Sort.Kind != LogicSortKind::BitVector)
return llvm::createStringError(
llvm::inconvertibleErrorCode(),
"logical function termination measure is not an integer");
if (!validateLogicCalls(Measure.get(), M.LogicFunctions,
ValidationError) ||
!validateVariableScopes(Measure.get(), ValidationError) ||
!validateDefinitionVariables(Measure.get(), Parameters, {},
ValidationError))
return llvm::createStringError(llvm::inconvertibleErrorCode(), "%s",
ValidationError.c_str());
}
}
return RequiredFeatures;
}
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/Verify/Backend/Obligation.h
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,8 @@ class LogicExpr : public llvm::ThreadSafeRefCountedBase<LogicExpr> {
std::vector<LogicExprRef> Patterns;
/// For an Or that states one assumption of a goal (`!A || rest`): where A
/// comes from (`pre`, `call:f`, `def:x_1`), so a goal can be shown as
/// named hypotheses. Outside the term's meaning, identity, and archives.
/// named hypotheses. Outside the term's meaning and identity; archives
/// keep it with their source metadata.
std::string Premise;

explicit LogicExpr(Kind K) : K(K) {}
Expand Down Expand Up @@ -355,7 +356,8 @@ struct LogicFunctionDecl {
/// value; a verdict that does rests on them. Not archived.
std::vector<std::unique_ptr<LogicExpr>> Postconditions;
/// A recursive function's termination measure over the parameters, by
/// which an induction over its applications descends. Not archived.
/// which an induction over its applications descends and Lean proves its
/// definition terminates. Archived, never hashed.
std::vector<std::unique_ptr<LogicExpr>> Decreases;
static constexpr const char *ResultVariable = "cppverify.result";
};
Expand Down
Loading
Loading