Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
120 commits
Select commit Hold shift + click to select a range
3788679
verify: Verify character literals, evaluated constants, template valu…
SwayamInSync Oct 27, 2026
f72c7d2
test: Small forms of everyday C++, each with a wrong twin.
SwayamInSync Oct 27, 2026
6d894ec
docs: Character literals are integers of their type.
SwayamInSync Oct 27, 2026
629f24b
docs: Initializer-list returns and structured bindings of records.
SwayamInSync Oct 27, 2026
de60746
docs: Default arguments, evaluated constants, declarations without ef…
SwayamInSync Oct 27, 2026
b910513
docs: List the small forms of everyday C++ in the supported fragment.
SwayamInSync Oct 27, 2026
6dfae45
docs: Note the small forms of everyday C++ in the 0.2.0 release notes.
SwayamInSync Oct 27, 2026
43c5124
docs: Describe how structured bindings are named.
SwayamInSync Oct 27, 2026
8af0c39
docs: Character literals in the book's switch example.
SwayamInSync Oct 27, 2026
79ce617
verify: Add the unreachable proof obligation kind.
SwayamInSync Oct 27, 2026
78f6b85
verify: Add Require, true where evaluating it requires its condition.
SwayamInSync Oct 27, 2026
904971b
verify: Name the unreachable kind, and lower Require to true.
SwayamInSync Oct 27, 2026
1b45b0b
verify: Archive the unreachable kind as tag 23.
SwayamInSync Oct 27, 2026
6d24c18
verify: Print Require in Layer 1 dumps.
SwayamInSync Oct 27, 2026
afa146d
verify: Make a lifted helper's asserts requirements of each call that…
SwayamInSync Oct 27, 2026
0b4d283
verify: Check a Require's condition where it is evaluated.
SwayamInSync Oct 27, 2026
5cccc1f
verify: Walk Require in the ownership scan.
SwayamInSync Oct 27, 2026
02d6a0f
verify: Walk Require in the UB scan.
SwayamInSync Oct 27, 2026
77a7765
verify: Verify assert, calls that do not return, assumptions, and dis…
SwayamInSync Oct 27, 2026
c11fe23
test: assert, calls that do not return, assumptions, discarded values…
SwayamInSync Oct 27, 2026
5f2da60
test: [[assume]] is proved, not rejected.
SwayamInSync Oct 27, 2026
faab2c5
test: Move the discarded sum, now checked, to assertions.cpp.
SwayamInSync Oct 27, 2026
8714e40
docs: Add the unreachable obligation kind.
SwayamInSync Oct 27, 2026
a23a043
docs: Describe assert and calls that do not return.
SwayamInSync Oct 27, 2026
4ae3219
docs: List assert, assumptions, and discarded values as supported.
SwayamInSync Oct 27, 2026
7d610bb
docs: Note assert and calls that do not return in the 0.2.0 release n…
SwayamInSync Oct 27, 2026
852219e
docs: Design assert, calls that do not return, and lifted helpers' as…
SwayamInSync Oct 27, 2026
7941874
docs: Describe Require and how a lifted helper's asserts are checked.
SwayamInSync Oct 27, 2026
d948b39
docs: Asserts and calls that do not return in the book.
SwayamInSync Oct 27, 2026
5fc32b2
Merge main into fix/assert.
SwayamInSync Oct 27, 2026
12c3c9e
verify: Read constant tables and string literals by index, as specs o…
SwayamInSync Oct 27, 2026
64b7305
test: Constant tables of one and two dimensions, string literals, and…
SwayamInSync Oct 27, 2026
b67f6d1
docs: Constant tables, read by index.
SwayamInSync Oct 27, 2026
e210577
docs: List constant tables in the storage row.
SwayamInSync Oct 27, 2026
2584b9f
docs: Note lookup tables in the 0.2.0 release notes.
SwayamInSync Oct 27, 2026
2b55087
docs: Design constant tables as values.
SwayamInSync Oct 27, 2026
0baf3b2
docs: Describe how a table read is lowered.
SwayamInSync Oct 27, 2026
649f7d2
docs: A constant table and a string literal in the book.
SwayamInSync Oct 27, 2026
83fc7a3
test: Cover non-square tables, a literal's last element, Boolean tabl…
SwayamInSync Oct 27, 2026
73d02f0
verify: List cppverify::index, an expression in a range-based for loo…
SwayamInSync Oct 27, 2026
3224fb7
verify: Declare and document cppverify::index.
SwayamInSync Oct 27, 2026
d8ebf76
verify: Diagnose cppverify::index outside a range-based for loop's co…
SwayamInSync Oct 27, 2026
3ed13ee
verify: Record a range-based for loop's position with its contract.
SwayamInSync Oct 27, 2026
7b3ae66
verify: Parse cppverify::index as the position of the range-based for…
SwayamInSync Oct 27, 2026
dd22462
verify: Declare a range-based for loop's position and keep its contract.
SwayamInSync Oct 27, 2026
065f41a
verify: Instantiate a range-based for loop's contract with its position.
SwayamInSync Oct 27, 2026
8ee3d28
verify: Visit a range-based for loop's contract.
SwayamInSync Oct 27, 2026
bdc8e4e
verify: Print a range-based for loop's clauses, its position as cppve…
SwayamInSync Oct 27, 2026
dad1148
verify: Dump a range-based for loop's clauses.
SwayamInSync Oct 27, 2026
6c5ef28
verify: Expose a range-based for loop's clauses as libclang cursors.
SwayamInSync Oct 27, 2026
260a9cc
verify: Verify range-based for loops over arrays, their position name…
SwayamInSync Oct 27, 2026
f3ae554
test: Range-based for loops over arrays, each with a wrong twin, and …
SwayamInSync Oct 27, 2026
1687d76
test: cppverify::index outside a range-based for loop's contract.
SwayamInSync Oct 27, 2026
d5a9314
test: Print a range-based for loop's clauses and parse them back.
SwayamInSync Oct 27, 2026
9b418be
test: Index the uses in a range-based for loop's contract.
SwayamInSync Oct 27, 2026
4e1517b
test: A range-based for loop's clauses as libclang cursors.
SwayamInSync Oct 27, 2026
14c1407
docs: List cppverify::index.
SwayamInSync Oct 27, 2026
3e61aa6
docs: Describe range-based for loops and cppverify::index.
SwayamInSync Oct 27, 2026
24dbc5c
docs: List range-based for loops over arrays as supported.
SwayamInSync Oct 27, 2026
d0f9605
docs: Note range-based for loops in the 0.2.0 release notes.
SwayamInSync Oct 27, 2026
6687b01
docs: Design range-based for loops and cppverify::index.
SwayamInSync Oct 27, 2026
ebc45f2
docs: Describe how a range-based for loop is lowered and where its po…
SwayamInSync Oct 27, 2026
c6ed751
docs: Loops over an array in the book.
SwayamInSync Oct 27, 2026
e90b81a
verify: Name unsupported constructs in C++ terms, report each once, a…
SwayamInSync Oct 27, 2026
b1cdcfd
test: Expect throw named as C++ names it.
SwayamInSync Oct 27, 2026
56033dc
test: Expect throw named as C++ names it in every output format.
SwayamInSync Oct 27, 2026
ad70b6a
test: Each unsupported construct named once, at its location.
SwayamInSync Oct 27, 2026
5d7cd36
test: Expressions that evaluate nothing at run time, with a wrong twin.
SwayamInSync Oct 27, 2026
ae4920e
docs: Describe how unsupported constructs are named, once.
SwayamInSync Oct 27, 2026
0a8b986
docs: Expressions that evaluate nothing at run time are their values.
SwayamInSync Oct 27, 2026
4b2c799
docs: List the expressions that evaluate nothing at run time as suppo…
SwayamInSync Oct 27, 2026
d94e39f
docs: Note named errors and constant expressions in the 0.2.0 release…
SwayamInSync Oct 27, 2026
e0430bf
docs: Describe how conversion errors name constructs and are raised o…
SwayamInSync Oct 27, 2026
8741bea
docs: Design expressions that evaluate nothing at run time as their v…
SwayamInSync Oct 27, 2026
9f4660d
verify: Count a run's verdicts, print under --quiet only what needs a…
SwayamInSync Oct 27, 2026
f1d17cb
verify: Add --quiet, --verbose, and --list-functions, end a run with …
SwayamInSync Oct 27, 2026
48a99be
test: The summary line, --quiet, --verbose, --list-functions, and the…
SwayamInSync Oct 27, 2026
6c9bcd3
test: A predicate whose rules are not established counts in the summa…
SwayamInSync Oct 27, 2026
fca5ee5
test: Expect no spec axiom lines in choose_reads.cpp.
SwayamInSync Oct 27, 2026
c61ef8c
test: Expect no spec axiom lines in class_templates.cpp.
SwayamInSync Oct 27, 2026
9d812a4
test: Expect no spec axiom lines in cov_multi_spec_z3.cpp.
SwayamInSync Oct 27, 2026
3dff3c5
test: Expect no spec axiom lines in cov_spec_fuel_exec.cpp.
SwayamInSync Oct 27, 2026
0c1fc02
test: Expect the summary line at the end of demoted_vacuity.cpp.
SwayamInSync Oct 27, 2026
714eb8f
test: Expect no spec axiom lines in function_templates.cpp.
SwayamInSync Oct 27, 2026
fce44aa
test: Expect no spec axiom lines, and the summary line, in interrupt.…
SwayamInSync Oct 27, 2026
e3cb706
test: Expect the summary line at the end of interrupt_certify.cpp.
SwayamInSync Oct 27, 2026
05b6d47
test: Expect the summary line at the end of interrupt_cvc5.cpp.
SwayamInSync Oct 27, 2026
b9f96ed
test: Expect the summary line at the end of lean_certifier_memory.test.
SwayamInSync Oct 27, 2026
6d8d320
test: Expect no spec axiom lines in lean_fallback_fast.cpp.
SwayamInSync Oct 27, 2026
3bf0499
test: Expect no spec axiom lines in logic_function_ir.cpp.
SwayamInSync Oct 27, 2026
2dbc679
test: Expect no spec axiom lines in lower_only_layers.cpp.
SwayamInSync Oct 27, 2026
498a073
test: Expect no spec axiom lines in mvp_factorial.cpp.
SwayamInSync Oct 27, 2026
df34fe2
test: Expect no spec axiom lines, and the summary line, in per_functi…
SwayamInSync Oct 27, 2026
3b0feda
test: Expect no spec axiom lines in safe_fib.cpp.
SwayamInSync Oct 27, 2026
7584243
test: Expect no spec axiom lines in solver_portfolio.cpp.
SwayamInSync Oct 27, 2026
3e140da
test: Expect no spec axiom lines in spec_inline_simple.cpp.
SwayamInSync Oct 27, 2026
4841297
test: Expect no spec axiom lines in spec_reads_exact.cpp.
SwayamInSync Oct 27, 2026
488c7e6
test: Expect no spec axiom lines in std_min_max.cpp.
SwayamInSync Oct 27, 2026
187b126
test: Expect no spec axiom lines in switch_statements.cpp.
SwayamInSync Oct 27, 2026
869b1c4
test: Expect no spec axiom lines in z3_constexpr_spec.cpp.
SwayamInSync Oct 27, 2026
179ca82
test: Expect no spec axiom lines in z3_hide_reveal_fuel.cpp.
SwayamInSync Oct 27, 2026
ddacaa1
test: Expect no spec axiom lines in z3_integer_widths.cpp.
SwayamInSync Oct 27, 2026
def615d
test: Expect no spec axiom lines in z3_overloads.cpp.
SwayamInSync Oct 27, 2026
91797b8
test: Expect no spec axiom lines in z3_quantified_specs.cpp.
SwayamInSync Oct 27, 2026
5bd551f
test: Expect no spec axiom lines in z3_spec_division.cpp.
SwayamInSync Oct 27, 2026
2f4b736
test: Expect no spec axiom lines in z3_spec_proof_axioms.cpp.
SwayamInSync Oct 27, 2026
6b1e7b5
test: Expect no spec axiom lines in verify_constexpr_spec_e2e.cpp.
SwayamInSync Oct 27, 2026
caec56e
test: Expect no spec axiom lines in verify_hide_reveal_e2e.cpp.
SwayamInSync Oct 27, 2026
b3c236e
docs: Describe the summary line, --quiet, --verbose, and --list-funct…
SwayamInSync Oct 27, 2026
5086808
docs: List --quiet, --verbose, and --list-functions in the book.
SwayamInSync Oct 27, 2026
16ccfb6
docs: Drop the spec axiom line from an example's output.
SwayamInSync Oct 27, 2026
c8ffeec
docs: Drop the spec axiom lines from the examples' output.
SwayamInSync Oct 27, 2026
816f629
docs: Drop the spec axiom line from the book's inductive example.
SwayamInSync Oct 27, 2026
3e93e5a
docs: Note the summary line and the new output options in the 0.2.0 r…
SwayamInSync Oct 27, 2026
dd4c421
docs: Describe how a run counts its verdicts for the summary.
SwayamInSync Oct 27, 2026
92ae2ea
test: Compare serial and parallel output without the summary's time i…
SwayamInSync Oct 27, 2026
f093c26
test: Compare serial and parallel output without the summary's time i…
SwayamInSync Oct 27, 2026
e31885b
test: Compare two runs without the summary's time in obligation_ir.cpp.
SwayamInSync Oct 27, 2026
a7bac1d
test: Compare two runs without the summary's time in logic_function_i…
SwayamInSync Oct 27, 2026
3b3a1cd
test: Compare the IR dumps of two runs without the summary's time in …
SwayamInSync Oct 27, 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
4 changes: 4 additions & 0 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,10 @@ struct LoopContractInfo {
SourceLocation MayDiverge;
/// The heap the loop may write, read in each iteration's state.
SmallVector<Expr *, 2> Modifies;
/// A range-based for loop's position, cppverify::index, which its clauses
/// may name: an implicit variable, the number of elements before the
/// current one.
VarDecl *Index = nullptr;

/// The clauses' expressions, as written.
SmallVector<Stmt *, 8> children() const {
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/AST/ASTDumper.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class ASTDumper : public ASTNodeTraverser<ASTDumper, TextNodeDumper> {
void VisitWhileStmt(const WhileStmt *S);
void VisitDoStmt(const DoStmt *S);
void VisitForStmt(const ForStmt *S);
void VisitCXXForRangeStmt(const CXXForRangeStmt *S);
};

} // namespace clang
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/AST/RecursiveASTVisitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -2667,6 +2667,7 @@ DEF_TRAVERSE_STMT(ObjCForCollectionStmt, {})
DEF_TRAVERSE_STMT(ObjCAutoreleasePoolStmt, {})

DEF_TRAVERSE_STMT(CXXForRangeStmt, {
TRY_TO(TraverseLoopContract(S));
if (!getDerived().shouldVisitImplicitCode()) {
if (S->getInit())
TRY_TO_TRAVERSE_OR_ENQUEUE_STMT(S->getInit());
Expand Down
1 change: 1 addition & 0 deletions clang/include/clang/Basic/CppVerifyConstructs.def
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ CPPVERIFY_CONSTRUCT(Exists, "exists", Expression)
CPPVERIFY_CONSTRUCT(Choose, "choose", Expression)
CPPVERIFY_CONSTRUCT(Old, "old", Expression)
CPPVERIFY_CONSTRUCT(Result, "result", Expression)
CPPVERIFY_CONSTRUCT(Index, "index", Expression)
CPPVERIFY_CONSTRUCT(Trigger, "trigger", Expression)

#undef CPPVERIFY_CONSTRUCT
3 changes: 3 additions & 0 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -1961,6 +1961,9 @@ def err_contract_redeclaration : Error<
"contract clauses may only be specified on one declaration of a function">;
def err_result_outside_postcondition : Error<
"'cppverify::result' can only be used in postconditions">;
def err_cppverify_index_outside_range_for : Error<
"'cppverify::index' is the position of a range-based for loop, in its "
"contract">;
def err_result_in_old_expression : Error<
"'cppverify::result' has no value in the function pre-state">;
def err_old_outside_postcondition : Error<
Expand Down
3 changes: 3 additions & 0 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -7668,6 +7668,9 @@ class Parser : public CodeCompletionHandler {
/// How many quantifier bodies enclose the current expression, where
/// trigger(term) marks a pattern.
unsigned QuantifierBodyDepth = 0;
/// The cppverify::index of the range-based for loop whose contract is
/// being parsed.
VarDecl *CppVerifyRangeIndex = nullptr;
/// True while parsing the operand of old(...).
bool InOldExpression = false;

Expand Down
13 changes: 13 additions & 0 deletions clang/lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,19 @@ void ASTDumper::VisitForStmt(const ForStmt *S) {
Visit(D, "decreases");
}

void ASTDumper::VisitCXXForRangeStmt(const CXXForRangeStmt *S) {
ASTNodeTraverser::VisitCXXForRangeStmt(S);
if (!Ctx)
return;
const LoopContractInfo *LCI = Ctx->getLoopContract(S);
if (!LCI)
return;
for (const Expr *E : LCI->Invariants)
Visit(E, "invariant");
for (const Expr *D : LCI->Decreases)
Visit(D, "decreases");
}

//===----------------------------------------------------------------------===//
// Type method implementations
//===----------------------------------------------------------------------===//
Expand Down
16 changes: 16 additions & 0 deletions clang/lib/AST/StmtPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/SaveAndRestore.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <optional>
Expand All @@ -73,6 +74,8 @@ namespace {
PrintingPolicy Policy;
std::string NL;
const ASTContext *Context;
/// The position of the range-based for loop whose clauses are printed.
const VarDecl *RangeIndex = nullptr;

public:
StmtPrinter(raw_ostream &os, PrinterHelper *helper,
Expand Down Expand Up @@ -490,6 +493,15 @@ void StmtPrinter::VisitCXXForRangeStmt(CXXForRangeStmt *Node) {
OS << " : ";
PrintExpr(Node->getRangeInit());
OS << ")";
const LoopContractInfo *LCI =
Context ? Context->getLoopContract(Node) : nullptr;
{
llvm::SaveAndRestore<const VarDecl *> Index(RangeIndex,
LCI ? LCI->Index : nullptr);
printLoopContract(
OS, Context, Node, [&]() -> raw_ostream & { return Indent(1); },
[&](Expr *E) { PrintExpr(E); }, NL);
}
PrintControlledStmt(Node->getBody());
}

Expand Down Expand Up @@ -1481,6 +1493,10 @@ void StmtPrinter::VisitConstantExpr(ConstantExpr *Node) {

void StmtPrinter::VisitDeclRefExpr(DeclRefExpr *Node) {
ValueDecl *VD = Node->getDecl();
if (RangeIndex && VD == RangeIndex) {
OS << "cppverify::index";
return;
}
if (const auto *OCED = dyn_cast<OMPCapturedExprDecl>(VD)) {
OCED->getInit()->IgnoreImpCasts()->printPretty(OS, nullptr, Policy);
return;
Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Headers/cppverify.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,10 @@ enum __construct {
/// The return value, in postconditions.
result __attribute__((unavailable("cppverify::result is the return value "
"in a postcondition"))),
/// In the contract of a range-based for loop: the number of elements
/// before the current one, from 0 to the size of the range.
index __attribute__((unavailable("cppverify::index is the position of a "
"range-based for loop in its contract"))),
/// After a spec function returning bool: the least predicate its body
/// defines, true exactly where a finite derivation shows it.
inductive __attribute__((unavailable("cppverify::inductive follows a spec "
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/Parse/ParseCppVerify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1245,6 +1245,15 @@ ExprResult Parser::ParseCppVerifyExpression() {
return ParseOldExpr();
case CppVerifyConstruct::Result:
return ParseResultExpr();
case CppVerifyConstruct::Index: {
const SourceLocation Loc = ConsumeCppVerify();
if (!CppVerifyRangeIndex) {
Diag(Loc, diag::err_cppverify_index_outside_range_for);
return ExprError();
}
return Actions.BuildDeclRefExpr(
CppVerifyRangeIndex, CppVerifyRangeIndex->getType(), VK_LValue, Loc);
}
case CppVerifyConstruct::Trigger: {
// trigger(term) in a quantifier body marks term as an instantiation
// pattern.
Expand Down
27 changes: 23 additions & 4 deletions clang/lib/Parse/ParseStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2309,10 +2309,24 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc,
// Match the ')'.
T.consumeClose();

// CppVerify: loop contract clauses before the body.
// CppVerify: loop contract clauses before the body. A range-based for
// loop's contract may name its position, cppverify::index.
LoopContractInfo ForContract;
if (getLangOpts().VerifyContracts)
if (getLangOpts().VerifyContracts) {
VarDecl *RangeIndex = nullptr;
if (ForRangeInfo.ParsedForRangeDecl()) {
ASTContext &Ctx = Actions.getASTContext();
QualType IndexType = Ctx.getPointerDiffType();
RangeIndex = VarDecl::Create(
Ctx, Actions.getContractBinderContext(), ForLoc, ForLoc,
&Ctx.Idents.get("__cppverify_index"), IndexType,
Ctx.getTrivialTypeSourceInfo(IndexType, ForLoc), SC_None);
RangeIndex->setImplicit();
}
llvm::SaveAndRestore<VarDecl *> Index(CppVerifyRangeIndex, RangeIndex);
ParseLoopContractClauses(ForContract);
ForContract.Index = RangeIndex;
}

// C++ Coroutines [stmt.iter]:
// 'co_await' can only be used for a range-based for statement.
Expand Down Expand Up @@ -2434,8 +2448,13 @@ StmtResult Parser::ParseForStatement(SourceLocation *TrailingElseLoc,
return Actions.FinishCXXExpansionStmt(ForRangeStmt.get(), Body.get());
}

if (ForRangeInfo.ParsedForRangeDecl())
return Actions.FinishCXXForRangeStmt(ForRangeStmt.get(), Body.get());
if (ForRangeInfo.ParsedForRangeDecl()) {
StmtResult RangeResult =
Actions.FinishCXXForRangeStmt(ForRangeStmt.get(), Body.get());
if (getLangOpts().VerifyContracts)
attachLoopContract(RangeResult, ForContract);
return RangeResult;
}

StmtResult ForResult = Actions.ActOnForStmt(
ForLoc, T.getOpenLocation(), FirstPart.get(), SecondPart, ThirdPart,
Expand Down
18 changes: 16 additions & 2 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -9430,9 +9430,14 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {

SemaRef.OpenACC().ActOnForStmtEnd(S->getBeginLoc(), Body);

std::optional<LoopContractInfo> Contract;
bool ContractChanged = false;
if (getDerived().TransformLoopContract(S, Contract, ContractChanged))
return StmtError();

// Body has changed but we didn't rebuild the for-range statement. Rebuild
// it now so we have a new statement to attach the body to.
if (Body.get() != S->getBody() && NewStmt.get() == S) {
if ((Body.get() != S->getBody() || ContractChanged) && NewStmt.get() == S) {
NewStmt = getDerived().RebuildCXXForRangeStmt(
S->getForLoc(), S->getCoawaitLoc(), Init.get(), S->getColonLoc(),
Range.get(), Begin.get(), End.get(), Cond.get(), Inc.get(),
Expand All @@ -9444,7 +9449,11 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
if (NewStmt.get() == S)
return S;

return FinishCXXForRangeStmt(NewStmt.get(), Body.get());
StmtResult Result = FinishCXXForRangeStmt(NewStmt.get(), Body.get());
if (Contract && Result.isUsable())
SemaRef.Context.getOrCreateLoopContract(Result.get()) =
std::move(*Contract);
return Result;
}

template <typename Derived>
Expand Down Expand Up @@ -18464,6 +18473,8 @@ VarDecl *TreeTransform<Derived>::TransformContractBinder(VarDecl *Binder) {
SemaRef.Context, Context, Binder->getBeginLoc(),
Binder->getLocation(), Binder->getIdentifier(), Binder->getType(),
Binder->getTypeSourceInfo(), SC_None);
if (Binder->isImplicit())
New->setImplicit();
getDerived().transformedLocalDecl(Binder, {New});
return New;
}
Expand Down Expand Up @@ -18588,6 +18599,9 @@ bool TreeTransform<Derived>::TransformLoopContract(
if (!From)
return false;
To.emplace();
// A range-based for loop's cppverify::index is declared with its contract.
if (From->Index)
To->Index = getDerived().TransformContractBinder(From->Index);
bool Invalid = false;
auto Keep = [&](Expr *Old, ExprResult New, SmallVectorImpl<Expr *> &Out) {
if (!New.isUsable()) {
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/Verify/Backend/Obligation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,8 @@ ObligationKind verify::obligationKind(ProofObligationKind Kind) {
return ObligationKind::Deallocation;
case ProofObligationKind::MissingReturn:
return ObligationKind::MissingReturn;
case ProofObligationKind::Unreachable:
return ObligationKind::Unreachable;
case ProofObligationKind::Unsupported:
return ObligationKind::Unsupported;
}
Expand Down Expand Up @@ -319,6 +321,8 @@ const char *verify::obligationKindName(ObligationKind Kind) {
return "deallocation";
case ObligationKind::MissingReturn:
return "missing-return";
case ObligationKind::Unreachable:
return "unreachable";
case ObligationKind::Unsupported:
return "unsupported";
}
Expand Down Expand Up @@ -2116,6 +2120,14 @@ class ObligationBuilder {
N->Children.push_back(std::move(Rhs));
return N;
}
// Its requirement is checked where it is evaluated; its value is true.
case VExpr::Require: {
auto N = std::make_unique<VCExpr>(VCExpr::BoolLit);
setBoolSort(*N);
N->Loc = E->Loc;
N->BoolVal = true;
return N;
}
}
return fail("unsupported VCR expression kind " +
std::to_string(static_cast<unsigned>(E->K)));
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Verify/Backend/Obligation.h
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ enum class ObligationKind {
Frame,
Deallocation,
MissingReturn,
Unreachable,
Unsupported
};

Expand Down
4 changes: 4 additions & 0 deletions clang/lib/Verify/Backend/ObligationSerialization.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,8 @@ uint8_t obligationTag(ObligationKind Kind) {
return 20;
case ObligationKind::MissingReturn:
return 21;
case ObligationKind::Unreachable:
return 23;
case ObligationKind::Unsupported:
return 22;
}
Expand Down Expand Up @@ -382,6 +384,8 @@ std::optional<ObligationKind> obligationFromTag(uint8_t Tag, uint32_t Version) {
return ObligationKind::MissingReturn;
case 22:
return ObligationKind::Unsupported;
case 23:
return ObligationKind::Unreachable;
default:
return std::nullopt;
}
Expand Down
9 changes: 9 additions & 0 deletions clang/lib/Verify/Driver/DumpIR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -206,6 +206,15 @@ void verify::dumpVExpr(const VExpr *E, llvm::raw_ostream &OS, unsigned Depth) {
dumpVExpr(O->Rhs.get(), OS, Depth + 1);
break;
}
case VExpr::Require: {
const auto *R = static_cast<const VRequireExpr *>(E);
OS << "require "
<< obligationKindName(
obligationKind(static_cast<ProofObligationKind>(R->ProofKind)))
<< "\n";
dumpVExpr(R->Cond.get(), OS, Depth + 1);
break;
}
}
}

Expand Down
Loading
Loading