From 1ef688f0f5be62cbafa74cea4e1ca612e35c639e Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:12 +0530 Subject: [PATCH 001/259] verify: Add the diagnostics a compilation reports verification results with. --- clang/include/clang/Basic/DiagnosticFrontendKinds.td | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index b001556966..c0b5b1587f 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -116,6 +116,10 @@ def err_fe_invalid_plugin_name : Error< "unable to find plugin '%0'">; def err_fe_cppverify_failed : Error< "cppverify: %0">; +def err_cppverify_result : Error<"%0">; +def warn_cppverify_result : Warning<"%0">, InGroup; +def remark_cppverify_result : Remark<"%0">, InGroup; +def note_cppverify_result : Note<"%0">; def err_fe_expected_compiler_job : Error< "unable to handle compilation, expected exactly one compiler job in '%0'">; def err_fe_expected_clang_command : Error< From 9e9c5997f2f0d20658e50bcae2e858cc3c9159fc Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:12 +0530 Subject: [PATCH 002/259] verify: Add the cppverify group for verification warnings and proof remarks. --- clang/include/clang/Basic/DiagnosticGroups.td | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td index 698f2cf108..82e548a976 100644 --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -1798,6 +1798,9 @@ Results can be filtered by function name by passing def : DiagGroup<"frame-larger-than=", [BackendFrameLargerThan]>; def BackendPlugin : DiagGroup<"backend-plugin">; def RemarkBackendPlugin : DiagGroup<"remark-backend-plugin">; +// cpp-verify's results in a compilation: its warnings, and its proofs as +// remarks. +def CppVerify : DiagGroup<"cppverify">; def BackendOptimizationRemark : DiagGroup<"pass">; def BackendOptimizationRemarkMissed : DiagGroup<"pass-missed">; def BackendOptimizationRemarkAnalysis : DiagGroup<"pass-analysis">; From 45fae1df3437a271409d975f2cbbbf736ba6abe5 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:13 +0530 Subject: [PATCH 003/259] verify: Make room for the verifier's frontend diagnostics. --- clang/include/clang/Basic/DiagnosticIDs.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/include/clang/Basic/DiagnosticIDs.h b/clang/include/clang/Basic/DiagnosticIDs.h index 63b5e6a28a..2d7e32579b 100644 --- a/clang/include/clang/Basic/DiagnosticIDs.h +++ b/clang/include/clang/Basic/DiagnosticIDs.h @@ -36,7 +36,7 @@ enum class Group; enum { DIAG_SIZE_COMMON = 300, DIAG_SIZE_DRIVER = 400, - DIAG_SIZE_FRONTEND = 200, + DIAG_SIZE_FRONTEND = 250, DIAG_SIZE_SERIALIZATION = 120, DIAG_SIZE_LEX = 500, DIAG_SIZE_PARSE = 800, From 05ad788641af544ad7b3fd410aa7e24251b5bd01 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:13 +0530 Subject: [PATCH 004/259] verify: Describe a verification result as Clang diagnostic parts. --- clang/lib/Verify/Driver/DiagnosticPart.h | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 clang/lib/Verify/Driver/DiagnosticPart.h diff --git a/clang/lib/Verify/Driver/DiagnosticPart.h b/clang/lib/Verify/Driver/DiagnosticPart.h new file mode 100644 index 0000000000..7dd03f8a76 --- /dev/null +++ b/clang/lib/Verify/Driver/DiagnosticPart.h @@ -0,0 +1,23 @@ +//===--- DiagnosticPart.h -------------------------------------------------===// +#ifndef LLVM_CLANG_VERIFY_DRIVER_DIAGNOSTICPART_H +#define LLVM_CLANG_VERIFY_DRIVER_DIAGNOSTICPART_H + +#include "clang/Basic/Diagnostic.h" +#include "clang/Basic/SourceLocation.h" +#include + +namespace clang { +namespace verify { + +/// One Clang diagnostic of a verification result: its line, or a note. +struct VerifyDiagnosticPart { + DiagnosticsEngine::Level Level = DiagnosticsEngine::Note; + SourceLocation Loc; + SourceRange Range; + std::string Message; +}; + +} // namespace verify +} // namespace clang + +#endif From 71cc14c728cff0d8a077eb0fc7c86a9448a16993 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:14 +0530 Subject: [PATCH 005/259] verify: Declare the counterexample and path step renderers. --- clang/lib/Verify/Driver/Counterexample.h | 27 ++++++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 clang/lib/Verify/Driver/Counterexample.h diff --git a/clang/lib/Verify/Driver/Counterexample.h b/clang/lib/Verify/Driver/Counterexample.h new file mode 100644 index 0000000000..9661471c3f --- /dev/null +++ b/clang/lib/Verify/Driver/Counterexample.h @@ -0,0 +1,27 @@ +//===--- Counterexample.h -------------------------------------------------===// +#ifndef LLVM_CLANG_VERIFY_DRIVER_COUNTEREXAMPLE_H +#define LLVM_CLANG_VERIFY_DRIVER_COUNTEREXAMPLE_H + +#include "../Backend/VerifyBackend.h" +#include + +namespace clang { +namespace verify { + +/// A counterexample's values by source name, in the order the source +/// declares them, each variable's versions in program order: +/// "a = 100, i = 0 -> 1, result = 151". Empty when it has none. +std::string counterexampleText(const VerifyResult &Result); + +/// One step of a counterexample's path, as the static analyzer words its +/// path notes: "takes the false branch", "returns 151". +std::string traceStepText(const VerifyTraceEvent &Event); + +/// How many steps of a path are shown: the first and last half of them, as +/// -ftemplate-backtrace-limit shows instantiation contexts. +inline constexpr size_t TraceStepLimit = 10; + +} // namespace verify +} // namespace clang + +#endif From 83a355ca3d65cada3514440d404ba24bdce74607 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:14 +0530 Subject: [PATCH 006/259] verify: Render counterexamples and path steps in source terms. --- clang/lib/Verify/Driver/Counterexample.cpp | 154 +++++++++++++++++++++ 1 file changed, 154 insertions(+) create mode 100644 clang/lib/Verify/Driver/Counterexample.cpp diff --git a/clang/lib/Verify/Driver/Counterexample.cpp b/clang/lib/Verify/Driver/Counterexample.cpp new file mode 100644 index 0000000000..8469cea8bb --- /dev/null +++ b/clang/lib/Verify/Driver/Counterexample.cpp @@ -0,0 +1,154 @@ +//===--- Counterexample.cpp -----------------------------------------------===// +#include "Counterexample.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/ADT/StringRef.h" +#include +#include +#include + +using namespace clang; +using namespace clang::verify; + +namespace { +/// An internal name's variable and SSA version: "i_2" is version 2 of "i", +/// "y#2_1" version 1 of the local that shadows y. +std::pair versionOf(llvm::StringRef InternalName) { + auto [Base, Suffix] = InternalName.rsplit('_'); + unsigned Version = 0; + if (Base.empty() || Suffix.getAsInteger(10, Version)) + return {InternalName, 0}; + return {Base, Version}; +} + +std::string valueText(const std::optional &Value) { + return Value.value_or(""); +} +} // namespace + +std::string verify::counterexampleText(const VerifyResult &Result) { + struct Variable { + const VerifyModelValue *First; + std::vector Versions; + }; + std::vector Variables; + std::map IndexOf; + std::map Named; + for (const VerifyModelValue &Value : Result.Model) { + // A version of a branch the path does not take is no value the variable + // takes; it equals the one before it there. + if (Value.OnPath == false) + continue; + auto [It, Inserted] = IndexOf.try_emplace( + versionOf(Value.InternalName).first, Variables.size()); + if (Inserted) { + Variables.push_back({&Value, {}}); + ++Named[Value.DisplayName]; + } + Variables[It->second].Versions.push_back(&Value); + } + auto position = [](const Variable &V) { + const ObligationSource &Source = V.First->Source; + return std::make_tuple(V.First->DisplayName == "result", !Source.isValid(), + Source.Line, Source.Column); + }; + std::stable_sort(Variables.begin(), Variables.end(), + [&](const Variable &A, const Variable &B) { + return position(A) < position(B); + }); + std::string Text; + for (Variable &V : Variables) { + std::stable_sort(V.Versions.begin(), V.Versions.end(), + [](const VerifyModelValue *A, const VerifyModelValue *B) { + return versionOf(A->InternalName).second < + versionOf(B->InternalName).second; + }); + // A reference's value is the address of what it refers to, which C++ + // writes &r. + Text += Text.empty() ? "" : ", "; + Text += (V.First->Reference ? "&" : "") + V.First->DisplayName; + // Two variables of one name, as a local that shadows another. + if (Named[V.First->DisplayName] > 1 && V.First->Source.isValid()) + Text += " (line " + std::to_string(V.First->Source.Line) + ")"; + Text += " = "; + // The values it takes in turn: a version that keeps the value before it, + // as one that merges branches, adds none. + const std::optional *Previous = nullptr; + for (const VerifyModelValue *Version : V.Versions) { + if (Previous && *Previous && *Previous == Version->Value) + continue; + Text += (Previous ? " -> " : "") + valueText(Version->Value); + Previous = &Version->Value; + } + } + return Text; +} + +std::string verify::traceStepText(const VerifyTraceEvent &Event) { + auto value = [&](llvm::StringRef Label) { + for (const VerifyTraceValue &Value : Event.Values) + if (Value.Label == Label) + return valueText(Value.Value); + return std::string(""); + }; + llvm::StringRef Message = Event.Message; + std::string Text; + switch (Event.Kind) { + case DiagnosticTraceKind::Branch: + Text = Message == "then" ? "takes the true branch" + : Message == "else" ? "takes the false branch" + : "takes the branch " + Message.str(); + break; + case DiagnosticTraceKind::Loop: + if (Message == "entry") + Text = "enters the loop"; + else if (Message == "inductive iteration") + Text = "starts an arbitrary iteration of the loop"; + else if (Message == "exit") + Text = "leaves the loop"; + else if (Message == "break") + Text = "breaks out of the loop"; + else if (Message == "continue") + Text = "continues the loop"; + else if (Message.consume_front("iteration ")) + Text = "runs iteration " + Message.str() + " of the loop"; + else if (Message.consume_front("exit after ")) + Text = "leaves the loop after " + Message.str() + + (Message == "1" ? " iteration" : " iterations"); + else + Text = "loop: " + Message.str(); + for (const VerifyTraceValue &Value : Event.Values) + if (Value.Label == "condition") + Text += ", where its condition is " + valueText(Value.Value); + break; + case DiagnosticTraceKind::Call: { + std::vector Arguments; + for (const VerifyTraceValue &Value : Event.Values) + Arguments.push_back(valueText(Value.Value)); + Text = "calls " + Message.str() + "(" + llvm::join(Arguments, ", ") + ")"; + break; + } + case DiagnosticTraceKind::HeapWrite: + Text = "stores " + value("value") + " at address " + value("address"); + break; + case DiagnosticTraceKind::Allocation: + Text = (Message == "automatic allocation" + ? "creates a local object at address " + : "allocates an object at address ") + + value("address"); + break; + case DiagnosticTraceKind::LifetimeEnd: + Text = "ends the lifetime of a local object"; + break; + case DiagnosticTraceKind::Deallocation: + Text = "deletes the object at address " + value("address"); + break; + case DiagnosticTraceKind::Return: + Text = Event.Values.empty() ? "returns" : "returns " + value("value"); + break; + } + if (!Event.Active) + Text = "perhaps " + Text + + " (the counterexample does not decide whether " + "this step is taken)"; + return Text; +} From 8b95b34ca257dd368b1ae10905fad13d68ab7e1b Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:15 +0530 Subject: [PATCH 007/259] verify: Build the counterexample renderer. --- clang/lib/Verify/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/lib/Verify/CMakeLists.txt b/clang/lib/Verify/CMakeLists.txt index 58327a2de8..a9cc217db0 100644 --- a/clang/lib/Verify/CMakeLists.txt +++ b/clang/lib/Verify/CMakeLists.txt @@ -48,6 +48,7 @@ add_clang_library(clangVerify Backend/VerifyBackend.cpp Backend/LeanBackend.cpp Driver/Verifier.cpp + Driver/Counterexample.cpp Driver/DumpIR.cpp Driver/CppVerifyIntegration.cpp Driver/CppVerifyVersion.cpp From 4dd5d14c65b31fb3ebafd0d87910912dc01f66b0 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:15 +0530 Subject: [PATCH 008/259] verify: Record where an expression begins. --- clang/lib/Verify/IR/VExpr.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/clang/lib/Verify/IR/VExpr.h b/clang/lib/Verify/IR/VExpr.h index 75324c847f..c0456a06a0 100644 --- a/clang/lib/Verify/IR/VExpr.h +++ b/clang/lib/Verify/IR/VExpr.h @@ -88,13 +88,16 @@ class VExpr { Kind K; VType Ty; SourceLocation Loc; + /// The source the expression spans, Loc being where in it a diagnostic + /// points (an operator's position, as Clang's getExprLoc). + SourceLocation BeginLoc; SourceLocation EndLoc; virtual ~VExpr() = default; protected: VExpr(Kind K, VType Ty, SourceLocation Loc) - : K(K), Ty(Ty), Loc(Loc), EndLoc(Loc) {} + : K(K), Ty(Ty), Loc(Loc), BeginLoc(Loc), EndLoc(Loc) {} }; class VLiteralExpr : public VExpr { From d7438053873c4a68930ba151ec5b92a0b451cc74 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:16 +0530 Subject: [PATCH 009/259] verify: Copy an expression's begin location with it. --- clang/lib/Verify/IR/VExpr.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clang/lib/Verify/IR/VExpr.cpp b/clang/lib/Verify/IR/VExpr.cpp index a362e0ceb6..ce98cfa5c6 100644 --- a/clang/lib/Verify/IR/VExpr.cpp +++ b/clang/lib/Verify/IR/VExpr.cpp @@ -254,8 +254,10 @@ VIntMode verify::evaluatedIntMode(const VExpr *E) { std::unique_ptr verify::cloneVExpr(const VExpr *E) { auto Copy = cloneVExprImpl(E); - if (Copy && E) + if (Copy && E) { + Copy->BeginLoc = E->BeginLoc; Copy->EndLoc = E->EndLoc; + } return Copy; } From b90489e16e7d4ee69c0f528a5b30ea9be22b5d82 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:16 +0530 Subject: [PATCH 010/259] verify: Mark source variables that are references. --- clang/lib/Verify/IR/VStmt.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang/lib/Verify/IR/VStmt.h b/clang/lib/Verify/IR/VStmt.h index 833f1e5c3b..1e5b0c75f4 100644 --- a/clang/lib/Verify/IR/VStmt.h +++ b/clang/lib/Verify/IR/VStmt.h @@ -319,6 +319,8 @@ struct VSourceVariable { VType Type; SourceLocation Loc; SourceLocation EndLoc; + /// A reference, whose value is the address of what it refers to. + bool Reference = false; }; /// reads(Base, Count) on a spec: the cells Base[0..Count), ElementSize bytes From 771f92fe95032dc7b91999cbf9f9ade46e0bd546 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:17 +0530 Subject: [PATCH 011/259] verify: Record where each expression begins and which variables are references. --- clang/lib/Verify/Frontend/ASTConverter.cpp | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/clang/lib/Verify/Frontend/ASTConverter.cpp b/clang/lib/Verify/Frontend/ASTConverter.cpp index 7da19f9b3e..b7a5dbac7f 100644 --- a/clang/lib/Verify/Frontend/ASTConverter.cpp +++ b/clang/lib/Verify/Frontend/ASTConverter.cpp @@ -145,8 +145,10 @@ static std::unique_ptr mathOperand(std::unique_ptr V) { } VType From = V->Ty; SourceLocation Loc = V->Loc; + SourceLocation BeginLoc = V->BeginLoc; SourceLocation EndLoc = V->EndLoc; auto Cast = std::make_unique(std::move(V), From, To, Loc); + Cast->BeginLoc = BeginLoc; Cast->EndLoc = EndLoc; return Cast; } @@ -1299,6 +1301,9 @@ void ASTConverter::recordSourceVariable(const ValueDecl *D) { } Record(InternalBase, DisplayBase, VType::fromQualType(D->getType(), IntMode, Ctx)); + if (auto It = CurrentFn->SourceVariables.find(InternalBase); + It != CurrentFn->SourceVariables.end()) + It->second.Reference = D->getType()->isReferenceType(); } bool ASTConverter::isDynamicAddress(const Expr *E) const { @@ -2559,6 +2564,7 @@ std::vector> ASTConverter::convertTranslationUnit() { // The post describes the spec where its body defines it. for (auto &Post : Fn->Postconditions) { const SourceLocation PostLoc = Post->Loc; + const SourceLocation PostBegin = Post->BeginLoc; const SourceLocation PostEnd = Post->EndLoc; Post = std::make_unique( VBinOp::Or, @@ -2566,6 +2572,7 @@ std::vector> ASTConverter::convertTranslationUnit() { cloneVExpr(Fn->Domain.get()), VType::makeBool(), PostLoc), std::move(Post), VType::makeBool(), PostLoc); + Post->BeginLoc = PostBegin; Post->EndLoc = PostEnd; } Unspecified.push_back(std::move(Outside)); @@ -5395,8 +5402,10 @@ std::unique_ptr ASTConverter::convertExpr(const Expr *E) { It->second, VType::fromQualType(E->getType(), IntMode, Ctx), E->getExprLoc()); auto Result = convertExprImpl(E); - if (Result && E) + if (Result && E) { + Result->BeginLoc = E->getBeginLoc(); Result->EndLoc = E->getEndLoc(); + } if (Result && E && isTriggerMarked(E)) markTrigger(Result, E); return Result; From fb42e152e11199c6714d1667f70811a23a0747fd Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:17 +0530 Subject: [PATCH 012/259] verify: Carry each model variable's path condition and reference flag. --- clang/lib/Verify/Transform/Passivize.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/clang/lib/Verify/Transform/Passivize.h b/clang/lib/Verify/Transform/Passivize.h index 2aac836e24..913228bb37 100644 --- a/clang/lib/Verify/Transform/Passivize.h +++ b/clang/lib/Verify/Transform/Passivize.h @@ -74,6 +74,11 @@ struct PassiveModelVariable { VType Type; SourceLocation Loc; SourceLocation EndLoc; + bool Reference = false; + /// The path condition where this version is defined, null on every path. + /// Elsewhere it equals the version before it, so only where the condition + /// holds is it a value the variable takes. + std::shared_ptr Guard; }; struct PassiveProgram { From 5e5ce9d67cd4e708ae997777ab996143da572015 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:18 +0530 Subject: [PATCH 013/259] verify: Record each variable version's path condition, and trace an operation after its own checks. --- clang/lib/Verify/Transform/Passivize.cpp | 41 +++++++++++++++++------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/clang/lib/Verify/Transform/Passivize.cpp b/clang/lib/Verify/Transform/Passivize.cpp index 4d3389bf76..885f6af6eb 100644 --- a/clang/lib/Verify/Transform/Passivize.cpp +++ b/clang/lib/Verify/Transform/Passivize.cpp @@ -174,8 +174,10 @@ static std::string stateVariableName(const CloneCtx &Ctx, static std::unique_ptr cloneExpr(const VExpr *E, const CloneCtx &Ctx) { auto Copy = cloneExprImpl(E, Ctx); - if (Copy && E) + if (Copy && E) { + Copy->BeginLoc = E->BeginLoc; Copy->EndLoc = E->EndLoc; + } return Copy; } @@ -2376,6 +2378,7 @@ collectSafety(const VExpr *E, const FunctionMap *FnMap, Collect(Expanded.get(), Inside); for (SafetyCheck &Check : Inside) { Check.Cond->Loc = C->Loc; + Check.Cond->BeginLoc = C->BeginLoc; Check.Cond->EndLoc = C->EndLoc; Out.push_back(std::move(Check)); } @@ -3611,6 +3614,9 @@ class PassivizerImpl { std::set HeapBases; std::set HeapVariables; std::map ModelVariables; + /// The path condition of the statement being passivized, for the versions + /// it defines. + const std::unique_ptr *VersionGuard = nullptr; std::map> SourceVersions; std::set SuppressedSourceVariables; std::vector TraceEvents; @@ -4320,9 +4326,13 @@ class PassivizerImpl { auto Source = Fn.SourceVariables.find(Base); if (Source == Fn.SourceVariables.end()) return; - ModelVariables[Versioned] = {Source->second.DisplayName, - Source->second.Type, Source->second.Loc, - Source->second.EndLoc}; + std::shared_ptr Guard; + if (VersionGuard && *VersionGuard) + Guard = cloneVExpr(VersionGuard->get()); + ModelVariables[Versioned] = { + Source->second.DisplayName, Source->second.Type, + Source->second.Loc, Source->second.EndLoc, + Source->second.Reference, std::move(Guard)}; SourceVersions[Base].insert(Versioned); } @@ -5239,9 +5249,11 @@ class PassivizerImpl { auto afterEarlier = [&](std::unique_ptr Cond) { if (!EarlierPosts) return Cond; - const SourceLocation Loc = Cond->Loc, End = Cond->EndLoc; + const SourceLocation Loc = Cond->Loc, Begin = Cond->BeginLoc, + End = Cond->EndLoc; auto Guarded = makeOr(makeNot(cloneVExpr(EarlierPosts.get()), Loc), std::move(Cond), Loc); + Guarded->BeginLoc = Begin; Guarded->EndLoc = End; return Guarded; }; @@ -5272,6 +5284,7 @@ class PassivizerImpl { // another file. auto Cond = cloneExpr(Check.Cond.get(), PCtx); Cond->Loc = Post->Loc; + Cond->BeginLoc = Post->BeginLoc; Cond->EndLoc = Post->EndLoc; P.ExitAsserts.push_back({Check.Kind, afterEarlier(std::move(Cond))}); } @@ -6357,6 +6370,8 @@ class PassivizerImpl { std::optional> Named; if (S.K != VStmt::Seq && S.K != VStmt::GhostBlock) Named.emplace(Origin, statementOrigin(S)); + llvm::SaveAndRestore *> Defining(VersionGuard, + &Active); switch (S.K) { case VStmt::Assign: { const auto &A = static_cast(S); @@ -6403,8 +6418,6 @@ class PassivizerImpl { std::vector TraceValues; TraceValues.push_back({"address", cloneVExpr(Ptr.get())}); TraceValues.push_back({"value", cloneVExpr(Val.get())}); - emitTrace(PassiveTraceKind::HeapWrite, "store", Active.get(), St.Loc, - std::move(TraceValues)); emitExprSafety(P, Ptr.get(), Active.get(), St.Loc, Renames, false, St.Ptr.get()); emitExprSafety(P, Val.get(), Active.get(), St.Loc, Renames, true, @@ -6499,6 +6512,8 @@ class PassivizerImpl { St.Loc); emitPassive(P, PassiveStmt::Assert, std::move(Allowed), Active.get(), St.Loc, ProofObligationKind::Frame); + emitTrace(PassiveTraceKind::HeapWrite, "store", Active.get(), St.Loc, + std::move(TraceValues)); std::string OldHeap = Renames[VHeapName]; std::string NewHeap = bump(VHeapName); Renames[VHeapName] = NewHeap; @@ -6793,8 +6808,6 @@ class PassivizerImpl { auto Pointer = cloneExpr(F.Ptr.get(), Ctx); std::vector TraceValues; TraceValues.push_back({"address", cloneVExpr(Pointer.get())}); - emitTrace(PassiveTraceKind::Deallocation, "delete", Active.get(), F.Loc, - std::move(TraceValues)); emitExprSafety(P, Pointer.get(), Active.get(), F.Loc, Renames, false, F.Ptr.get()); auto Provenance = pointerProvenance(Pointer.get()); @@ -6805,6 +6818,8 @@ class PassivizerImpl { std::make_unique(0, VType::makePtr(), F.Loc), F.Loc), Active.get(), F.Loc, ProofObligationKind::Deallocation); + emitTrace(PassiveTraceKind::Deallocation, "delete", Active.get(), F.Loc, + std::move(TraceValues)); break; } auto IsNull = makeEq( @@ -6840,6 +6855,8 @@ class PassivizerImpl { F.Loc); emitPassive(P, PassiveStmt::Assert, std::move(Owned), Active.get(), F.Loc, ProofObligationKind::Deallocation); + emitTrace(PassiveTraceKind::Deallocation, "delete", Active.get(), F.Loc, + std::move(TraceValues)); auto LivenessAfterDelete = std::make_unique( cloneVExpr(IsNull.get()), cloneVExpr(Live.get()), makeBoolLiteral(false, F.Loc), VType::makeBool(), F.Loc); @@ -6941,12 +6958,14 @@ class PassivizerImpl { break; } auto BoundReturn = cloneExpr(R.Value.get(), Ctx); + // A step of the path is one that happens: a check of the value comes + // before the return, which a failure of the check never reaches. + emitExprSafety(P, BoundReturn.get(), Active.get(), R.Loc, Renames, true, + R.Value.get()); std::vector TraceValues; TraceValues.push_back({"value", cloneVExpr(BoundReturn.get())}); emitTrace(PassiveTraceKind::Return, "return", Active.get(), R.Loc, std::move(TraceValues)); - emitExprSafety(P, BoundReturn.get(), Active.get(), R.Loc, Renames, true, - R.Value.get()); const VExpr *RetVal = R.Value.get(); while (RetVal && RetVal->K == VExpr::Cast) RetVal = static_cast(RetVal)->Inner.get(); From 21e56090b191d05d5e94e89c11b5e9d1838cb6cf Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:18 +0530 Subject: [PATCH 014/259] verify: Keep begin locations through spec inlining. --- clang/lib/Verify/Transform/SpecInline.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/clang/lib/Verify/Transform/SpecInline.cpp b/clang/lib/Verify/Transform/SpecInline.cpp index 0b3a5d5c87..93c24cc8c7 100644 --- a/clang/lib/Verify/Transform/SpecInline.cpp +++ b/clang/lib/Verify/Transform/SpecInline.cpp @@ -137,6 +137,7 @@ class SpecInlinerImpl { const VSpecCallExpr &Call) { if (Expr) { Expr->Loc = Call.Loc; + Expr->BeginLoc = Call.BeginLoc; Expr->EndLoc = Call.EndLoc; } return Expr; @@ -559,8 +560,10 @@ class SpecInlinerImpl { evalExpr(const VExpr *E, const std::map> &Env) { auto Result = evalExprImpl(E, Env); - if (Result && E) + if (Result && E) { + Result->BeginLoc = E->BeginLoc; Result->EndLoc = E->EndLoc; + } return Result; } From 2a38044600b634bea66908602e40e3fdca1f0973 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:19 +0530 Subject: [PATCH 015/259] verify: Carry variable version guards and expression begin locations in obligation modules. --- clang/lib/Verify/Backend/Obligation.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/clang/lib/Verify/Backend/Obligation.h b/clang/lib/Verify/Backend/Obligation.h index 188590a5ba..3998753961 100644 --- a/clang/lib/Verify/Backend/Obligation.h +++ b/clang/lib/Verify/Backend/Obligation.h @@ -209,6 +209,7 @@ class LogicExpr : public llvm::ThreadSafeRefCountedBase { Kind K; LogicSort Sort; SourceLocation Loc; + SourceLocation BeginLoc; SourceLocation EndLoc; /// Where Loc lies, filled in by the driver once the term is built /// (annotateObligationSources): the one field written after a term is @@ -312,6 +313,7 @@ struct Obligation { std::string StableId; ObligationKind Kind = ObligationKind::Assertion; SourceLocation Loc; + SourceLocation BeginLoc; SourceLocation EndLoc; ObligationSource Source; uint64_t TraceEventCount = 0; @@ -328,6 +330,11 @@ struct DiagnosticVariable { SourceLocation Loc; SourceLocation EndLoc; ObligationSource Source; + /// A reference: its value is the address it refers to. Not archived. + bool Reference = false; + /// Where this version is defined, as PassiveModelVariable::Guard (true on + /// every path); null when unknown, as in an archive before version 4. + LogicExprRef Guard = nullptr; }; struct LogicFunctionParameter { From 9990f03f065c8d2c9f35a61feaa031f78eb309d9 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:19 +0530 Subject: [PATCH 016/259] verify: Lower where each variable version is defined and where each expression begins. --- clang/lib/Verify/Backend/Obligation.cpp | 34 ++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/clang/lib/Verify/Backend/Obligation.cpp b/clang/lib/Verify/Backend/Obligation.cpp index e6970cece7..976d229d1d 100644 --- a/clang/lib/Verify/Backend/Obligation.cpp +++ b/clang/lib/Verify/Backend/Obligation.cpp @@ -1745,8 +1745,10 @@ class ObligationBuilder { std::unique_ptr fromVExpr(const VExpr *E) { auto Result = fromVExprImpl(E); - if (Result && E) + if (Result && E) { + Result->BeginLoc = E->BeginLoc; Result->EndLoc = E->EndLoc; + } return Result; } @@ -2173,8 +2175,9 @@ class ObligationBuilder { fail("invalid diagnostic variable sort in obligation lowering"); continue; } - M.DiagnosticVariables[InternalName] = { - Variable.DisplayName, Sort, Variable.Loc, Variable.EndLoc, {}}; + DiagnosticVariable &Diagnostic = M.DiagnosticVariables[InternalName]; + Diagnostic = {Variable.DisplayName, Sort, Variable.Loc, Variable.EndLoc}; + Diagnostic.Reference = Variable.Reference; } auto traceKind = [](PassiveTraceKind Kind) { switch (Kind) { @@ -2216,6 +2219,17 @@ class ObligationBuilder { {Value.Label, lowerDiagnosticExpr(Value.Value.get())}); M.TraceEvents.push_back(std::move(Lowered)); } + auto Everywhere = std::make_unique(VCExpr::BoolLit); + setBoolSort(*Everywhere); + Everywhere->BoolVal = true; + const LogicExprRef OnEveryPath(std::move(Everywhere)); + for (const auto &[InternalName, Variable] : P.ModelVariables) + if (auto It = M.DiagnosticVariables.find(InternalName); + It != M.DiagnosticVariables.end()) + It->second.Guard = + Variable.Guard + ? LogicExprRef(lowerDiagnosticExpr(Variable.Guard.get())) + : OnEveryPath; std::vector> EntryAssumes; for (const auto &Entry : P.EntryAssumes) @@ -2289,6 +2303,7 @@ class ObligationBuilder { ConditionWP->Premise = It->second.empty() ? "fact" : It->second; } ConditionWP->Loc = Condition->Loc; + ConditionWP->BeginLoc = Condition->BeginLoc; ConditionWP->EndLoc = Condition->EndLoc; return ConditionWP; }; @@ -2305,12 +2320,14 @@ class ObligationBuilder { Item.Kind = Kind; Item.Note = Note; Item.Loc = Condition->Loc; + Item.BeginLoc = Condition->BeginLoc; Item.EndLoc = Condition->EndLoc; Item.TraceEventCount = TraceEventCount; Item.Id = Identity + "::obligation:" + std::to_string(++ObligationIndex); Item.Goal = makeGoal(Condition); Item.CounterexampleQuery = vcNot(cloneLogicExpr(Item.Goal.get())); Item.CounterexampleQuery->Loc = Condition->Loc; + Item.CounterexampleQuery->BeginLoc = Condition->BeginLoc; Item.CounterexampleQuery->EndLoc = Condition->EndLoc; M.Obligations.push_back(std::move(Item)); }; @@ -2406,6 +2423,17 @@ verify::validateObligationModule(const ObligationModule &M) { llvm::inconvertibleErrorCode(), "obligation module has invalid diagnostic trace value"); } + for (const auto &[InternalName, Variable] : M.DiagnosticVariables) + if (Variable.Guard && + (!validateLogicExpr(Variable.Guard.get(), ValidationError) || + !validateLogicCalls(Variable.Guard.get(), M.LogicFunctions, + ValidationError) || + !validateVariableScopes(Variable.Guard.get(), ModuleVariables, + ValidationError) || + Variable.Guard->Sort.Kind != LogicSortKind::Bool)) + return llvm::createStringError( + llvm::inconvertibleErrorCode(), + "obligation module has an invalid diagnostic variable guard"); if (!validateLogicExpr(M.CorrectnessGoal.get(), ValidationError)) return llvm::createStringError(llvm::inconvertibleErrorCode(), "%s", ValidationError.c_str()); From bee1bbdc93607fc3db393dc59e452de31fa762da Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:19 +0530 Subject: [PATCH 017/259] verify: Keep begin locations in simplification, and drop a guard that calls a removed function. --- clang/lib/Verify/Backend/ObligationSimplify.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/clang/lib/Verify/Backend/ObligationSimplify.cpp b/clang/lib/Verify/Backend/ObligationSimplify.cpp index 66154f06fe..5ea04c4b74 100644 --- a/clang/lib/Verify/Backend/ObligationSimplify.cpp +++ b/clang/lib/Verify/Backend/ObligationSimplify.cpp @@ -20,6 +20,7 @@ std::unique_ptr cloneLogicExpr(const LogicExpr *Expr) { auto Copy = std::make_unique(Expr->K); Copy->Sort = Expr->Sort; Copy->Loc = Expr->Loc; + Copy->BeginLoc = Expr->BeginLoc; Copy->EndLoc = Expr->EndLoc; Copy->Source = Expr->Source; Copy->IntVal = Expr->IntVal; @@ -99,6 +100,7 @@ std::unique_ptr boolLiteral(bool Value, const LogicExpr &Source) { std::make_unique(Value ? LogicExpr::True : LogicExpr::False); Result->Sort = LogicSort::boolSort(); Result->Loc = Source.Loc; + Result->BeginLoc = Source.BeginLoc; Result->EndLoc = Source.EndLoc; Result->Source = Source.Source; return Result; @@ -140,6 +142,7 @@ LogicExprRef lowerUnsignedMathArithmetic(const LogicExprRef &Expr, auto Divisor = std::make_unique(LogicExpr::IntLit); Divisor->Sort = SourceSort; Divisor->Loc = Expr->Children[1]->Loc; + Divisor->BeginLoc = Expr->Children[1]->BeginLoc; Divisor->EndLoc = Expr->Children[1]->EndLoc; Divisor->Source = Expr->Children[1]->Source; Divisor->IntVal = Expr->Children[1]->IntVal; @@ -147,6 +150,7 @@ LogicExprRef lowerUnsignedMathArithmetic(const LogicExprRef &Expr, auto MachineArithmetic = std::make_unique(Expr->K); MachineArithmetic->Sort = SourceSort; MachineArithmetic->Loc = Expr->Loc; + MachineArithmetic->BeginLoc = Expr->BeginLoc; MachineArithmetic->EndLoc = Expr->EndLoc; MachineArithmetic->Source = Expr->Source; MachineArithmetic->Children.push_back( @@ -182,6 +186,7 @@ simplifyUnsignedMathToBitVector(const LogicExprRef &Expr, auto Resize = std::make_unique(LogicExpr::BvResize); Resize->Sort = Expr->Sort; Resize->Loc = Expr->Loc; + Resize->BeginLoc = Expr->BeginLoc; Resize->EndLoc = Expr->EndLoc; Resize->Source = Expr->Source; Resize->Children.push_back(std::move(MachineArithmetic)); @@ -297,6 +302,7 @@ std::unique_ptr negate(std::unique_ptr Expr) { Result->Sort = LogicSort::boolSort(); if (Expr) { Result->Loc = Expr->Loc; + Result->BeginLoc = Expr->BeginLoc; Result->EndLoc = Expr->EndLoc; Result->Source = Expr->Source; } @@ -316,6 +322,7 @@ buildCompleteGoal(const std::vector &Obligations) { auto Conjunction = std::make_unique(LogicExpr::And); Conjunction->Sort = LogicSort::boolSort(); Conjunction->Loc = Complete->Loc; + Conjunction->BeginLoc = Complete->BeginLoc; Conjunction->EndLoc = Complete->EndLoc; Conjunction->Source = Complete->Source; Conjunction->Children.push_back(std::move(Complete)); @@ -389,6 +396,10 @@ void simplifyFunctions(ObligationModule &Module, }), Event.Values.end()); } + for (auto &[InternalName, Variable] : Module.DiagnosticVariables) + if (Variable.Guard && + !callsOnlyReachableFunctions(Variable.Guard.get(), Reachable)) + Variable.Guard = nullptr; for (auto It = Module.LogicFunctions.begin(); It != Module.LogicFunctions.end();) { @@ -428,6 +439,7 @@ std::unique_ptr substituteVariable(const LogicExpr *Expr, auto Copy = std::make_unique(Expr->K); Copy->Sort = Expr->Sort; Copy->Loc = Expr->Loc; + Copy->BeginLoc = Expr->BeginLoc; Copy->EndLoc = Expr->EndLoc; Copy->Source = Expr->Source; Copy->IntVal = Expr->IntVal; @@ -450,6 +462,7 @@ std::unique_ptr logicNode(LogicExpr::Kind K, LogicSort Sort, auto Node = std::make_unique(K); Node->Sort = Sort; Node->Loc = At.Loc; + Node->BeginLoc = At.BeginLoc; Node->EndLoc = At.EndLoc; Node->Source = At.Source; return Node; From e18f06f5ceca639800dd87429af0eac73031d85b Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:20 +0530 Subject: [PATCH 018/259] verify: Move obligation archives to schema v4. --- clang/lib/Verify/Backend/ObligationSerialization.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Verify/Backend/ObligationSerialization.h b/clang/lib/Verify/Backend/ObligationSerialization.h index 944dcd85e8..7bb75427dd 100644 --- a/clang/lib/Verify/Backend/ObligationSerialization.h +++ b/clang/lib/Verify/Backend/ObligationSerialization.h @@ -15,7 +15,7 @@ namespace verify { /// Version 2 adds the precise obligation kinds; version 3 each logical /// function's termination measures and, with source metadata, where each /// assumption of a goal comes from. Readers read every earlier version. -inline constexpr uint32_t ObligationSerializationVersion = 3; +inline constexpr uint32_t ObligationSerializationVersion = 4; inline constexpr uint32_t ObligationSemanticHashVersion = 4; /// Serialize one module as a deterministic, versioned binary record. Records From 23666cbe5a062bef06d7677a4d0dcfeda4fe967f Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:20 +0530 Subject: [PATCH 019/259] verify: Archive where each variable version is defined, from schema v4. --- clang/lib/Verify/Backend/ObligationSerialization.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/clang/lib/Verify/Backend/ObligationSerialization.cpp b/clang/lib/Verify/Backend/ObligationSerialization.cpp index 5cd365ff37..f15b9cdbca 100644 --- a/clang/lib/Verify/Backend/ObligationSerialization.cpp +++ b/clang/lib/Verify/Backend/ObligationSerialization.cpp @@ -584,6 +584,11 @@ class ArchiveWriter { writeString(Variable.DisplayName); writeSort(Variable.Sort); writeSource(Variable.Source); + if (FormatVersion >= 4) { + writeU8(Variable.Guard ? 1 : 0); + if (Variable.Guard) + writeExpr(Variable.Guard.get()); + } } writeU64(Module.TraceEvents.size()); for (const DiagnosticTraceEvent &Event : Module.TraceEvents) { @@ -899,6 +904,13 @@ class ArchiveReader { Variable.DisplayName = readString(); Variable.Sort = readSort(); Variable.Source = readSource(IncludeSource); + if (Version >= 4) { + uint8_t HasGuard = readU8(); + if (HasGuard > 1) + fail("invalid diagnostic variable guard in obligation archive"); + if (HasGuard == 1) + Variable.Guard = LogicExprRef(readExpr()); + } if (!Module.DiagnosticVariables .emplace(std::move(InternalName), std::move(Variable)) .second) From e7e1aa4b3078f19504bdbaa23573f96ef06d5f2a Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:21 +0530 Subject: [PATCH 020/259] verify: Keep begin locations when an induction copies a module. --- clang/lib/Verify/Backend/Induction.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang/lib/Verify/Backend/Induction.cpp b/clang/lib/Verify/Backend/Induction.cpp index c91b84bdec..2f422fc21e 100644 --- a/clang/lib/Verify/Backend/Induction.cpp +++ b/clang/lib/Verify/Backend/Induction.cpp @@ -21,6 +21,7 @@ std::unique_ptr node(LogicExpr::Kind K, LogicSort Sort, Node->Sort = Sort; if (At) { Node->Loc = At->Loc; + Node->BeginLoc = At->BeginLoc; Node->EndLoc = At->EndLoc; Node->Source = At->Source; } @@ -722,6 +723,7 @@ ObligationModule copyObligationModule(const ObligationModule &Module) { Same.StableId = Item.StableId; Same.Kind = Item.Kind; Same.Loc = Item.Loc; + Same.BeginLoc = Item.BeginLoc; Same.EndLoc = Item.EndLoc; Same.Source = Item.Source; Same.TraceEventCount = Item.TraceEventCount; From 52b8ac2cb3499d628520a61c0ef9d7c13cc70dba Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:21 +0530 Subject: [PATCH 021/259] verify: Carry the failing expression's start, and each value's path and reference flags, in results. --- clang/lib/Verify/Backend/VerifyBackend.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/clang/lib/Verify/Backend/VerifyBackend.h b/clang/lib/Verify/Backend/VerifyBackend.h index fe41b6428e..8cf3cea9fa 100644 --- a/clang/lib/Verify/Backend/VerifyBackend.h +++ b/clang/lib/Verify/Backend/VerifyBackend.h @@ -91,6 +91,12 @@ struct VerifyModelValue { /// Empty when the solver model does not determine this value. Backends must /// not use model completion to manufacture a diagnostic value. std::optional Value; + /// A reference: Value is the address it refers to. + bool Reference = false; + /// Whether the counterexample's path reaches where this version is + /// defined: false for a version of a branch it does not take, empty when + /// the model does not decide it or nothing records it. + std::optional OnPath; }; struct VerifyTraceValue { @@ -102,6 +108,7 @@ struct VerifyTraceValue { struct VerifyTraceEvent { DiagnosticTraceKind Kind = DiagnosticTraceKind::Branch; std::string Message; + SourceLocation Loc; ObligationSource Source; /// Empty when the model does not determine whether this event is on the /// counterexample path. @@ -148,6 +155,10 @@ struct VerifyResult { /// goal of the obligation it fails, when the model gives each one. std::shared_ptr Assignment; SourceLocation Location; + /// The source the failing obligation's expression spans; Location lies + /// in it. + SourceLocation BeginLocation; + SourceLocation EndLocation; ObligationSource Source; uint64_t CacheHits = 0; uint64_t CacheMisses = 0; From 7b3e472e0214528500bf99835d57b421fe536eb9 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:22 +0530 Subject: [PATCH 022/259] verify: Reset a result's begin location with its location. --- clang/lib/Verify/Backend/VerifyBackend.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/clang/lib/Verify/Backend/VerifyBackend.cpp b/clang/lib/Verify/Backend/VerifyBackend.cpp index b61a3852be..71055135a1 100644 --- a/clang/lib/Verify/Backend/VerifyBackend.cpp +++ b/clang/lib/Verify/Backend/VerifyBackend.cpp @@ -629,6 +629,8 @@ VerifyResult VerifyBackend::verifyDirect(const ObligationModule &Module) { Result.ObligationId.clear(); Result.ObligationType.reset(); Result.Location = SourceLocation(); + Result.BeginLocation = SourceLocation(); + Result.EndLocation = SourceLocation(); Result.Source = {}; } else if (Capabilities.ProducesVerificationVerdict && (Result.Status == VerifyStatus::Exported || @@ -642,6 +644,8 @@ VerifyResult VerifyBackend::verifyDirect(const ObligationModule &Module) { Result.ObligationId.clear(); Result.ObligationType.reset(); Result.Location = SourceLocation(); + Result.BeginLocation = SourceLocation(); + Result.EndLocation = SourceLocation(); Result.Source = {}; } // A model of `false` says nothing about the program. From d2cd70a1609d35614246be24eb19249f0d1da037 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:22 +0530 Subject: [PATCH 023/259] verify: Evaluate whether each counterexample value lies on its path. --- clang/lib/Verify/Backend/Z3Encode.cpp | 70 ++++++--------------------- 1 file changed, 15 insertions(+), 55 deletions(-) diff --git a/clang/lib/Verify/Backend/Z3Encode.cpp b/clang/lib/Verify/Backend/Z3Encode.cpp index fd2483b947..9b95023693 100644 --- a/clang/lib/Verify/Backend/Z3Encode.cpp +++ b/clang/lib/Verify/Backend/Z3Encode.cpp @@ -3354,6 +3354,8 @@ VerifyResult Z3Encoder::decideModule(const ObligationModule &Module, Out.ObligationId = Item.StableId.empty() ? Item.Id : Item.StableId; Out.ObligationType = Item.Kind; Out.Location = Item.Loc; + Out.BeginLocation = Item.BeginLoc; + Out.EndLocation = Item.EndLoc; Out.Source = Item.Source; Out.Assignment = assignment(Item); TraceEventCount = Item.TraceEventCount; @@ -3390,6 +3392,11 @@ VerifyResult Z3Encoder::decideModule(const ObligationModule &Module, return Out; } Value.Source = Metadata->second.Source; + Value.Reference = Metadata->second.Reference; + if (Metadata->second.Guard) + if (std::optional Guard = + evaluate(Metadata->second.Guard.get())) + Value.OnPath = *Guard == "true"; } if (auto It = Vars.find(Name); It != Vars.end()) { z3::expr Evaluated = modelValue(It->second); @@ -3409,6 +3416,7 @@ VerifyResult Z3Encoder::decideModule(const ObligationModule &Module, VerifyTraceEvent Trace; Trace.Kind = Event.Kind; Trace.Message = Event.Message; + Trace.Loc = Event.Loc; Trace.Source = Event.Source; if (Guard) Trace.Active = *Guard == "true"; @@ -3486,62 +3494,11 @@ static VerifyResult timeSpent() { return Result; } +/// A failure's values and path are its Model and Trace, which the driver +/// prints; its Message only explains what they do not say. static VerifyResult finishZ3Result(VerifyResult Result) { - if (Result.Status != VerifyStatus::Failed) - return Result; - std::string Message; - for (const VerifyModelValue &Value : Result.Model) { - if (!Message.empty()) - Message += ", "; - Message += Value.DisplayName; - if (Value.DisplayName != Value.InternalName) - Message += " [ssa=" + Value.InternalName + "]"; - Message += " [type=" + formatLogicSort(Value.Sort) + - "] = " + Value.Value.value_or(""); - } - auto traceKind = [](DiagnosticTraceKind Kind) { - switch (Kind) { - case DiagnosticTraceKind::Branch: - return "branch"; - case DiagnosticTraceKind::Call: - return "call"; - case DiagnosticTraceKind::Loop: - return "loop"; - case DiagnosticTraceKind::HeapWrite: - return "heap-write"; - case DiagnosticTraceKind::Allocation: - return "allocation"; - case DiagnosticTraceKind::LifetimeEnd: - return "lifetime-end"; - case DiagnosticTraceKind::Deallocation: - return "deallocation"; - case DiagnosticTraceKind::Return: - return "return"; - } - return "branch"; - }; - if (!Result.Trace.empty()) { - if (!Message.empty()) - Message += "; "; - Message += "trace: "; - bool First = true; - for (const VerifyTraceEvent &Event : Result.Trace) { - if (!First) - Message += " -> "; - First = false; - Message += traceKind(Event.Kind); - if (!Event.Message.empty()) - Message += "." + Event.Message; - if (Event.Source.isValid()) - Message += "@" + std::to_string(Event.Source.Line) + ":" + - std::to_string(Event.Source.Column); - if (!Event.Active) - Message += "?"; - for (const VerifyTraceValue &Value : Event.Values) - Message += " " + Value.Label + "=" + Value.Value.value_or(""); - } - } - Result.Message = std::move(Message); + if (Result.Status == VerifyStatus::Failed) + Result.Message.clear(); return Result; } @@ -3782,6 +3739,8 @@ static VerifyResult attributed(VerifyResult Result, const Obligation &Item) { Result.ObligationId = Item.StableId.empty() ? Item.Id : Item.StableId; Result.ObligationType = Item.Kind; Result.Location = Item.Loc; + Result.BeginLocation = Item.BeginLoc; + Result.EndLocation = Item.EndLoc; Result.Source = Item.Source; if (Result.Status == VerifyStatus::Unresolved) Result.Message = "proof obligation " + Result.ObligationId + @@ -3849,6 +3808,7 @@ Z3VerifyBackend::verifyPastEarlier(const ObligationModule &Module, size_t I, auto Conjunction = std::make_unique(LogicExpr::And); Conjunction->Sort = LogicSort::boolSort(); Conjunction->Loc = Query->Loc; + Conjunction->BeginLoc = Query->BeginLoc; Conjunction->EndLoc = Query->EndLoc; Conjunction->Source = Query->Source; Conjunction->Children.push_back(std::move(Query)); From 4ac5b620087ff17b5da5c5ce1691441fdaac6b74 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:23 +0530 Subject: [PATCH 024/259] verify: Keep the start of the failing expression in cvc5 results. --- clang/lib/Verify/Backend/CVC5Backend.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang/lib/Verify/Backend/CVC5Backend.cpp b/clang/lib/Verify/Backend/CVC5Backend.cpp index 0ecff37ad3..9d9a1fa0fc 100644 --- a/clang/lib/Verify/Backend/CVC5Backend.cpp +++ b/clang/lib/Verify/Backend/CVC5Backend.cpp @@ -2838,6 +2838,8 @@ VerifyResult CVC5VerifyBackend::verifyObligation(const ObligationModule &Module, Result.ObligationId = Item.StableId.empty() ? Item.Id : Item.StableId; Result.ObligationType = Item.Kind; Result.Location = Item.Loc; + Result.BeginLocation = Item.BeginLoc; + Result.EndLocation = Item.EndLoc; Result.Source = Item.Source; if (Result.Status == VerifyStatus::Unresolved) Result.Message = "proof obligation " + Result.ObligationId + From 4d2b72eb279cfa98d29ffd6c2e6509a86cb92d74 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:23 +0530 Subject: [PATCH 025/259] verify: Mark references among the values of an unchecked counterexample. --- clang/lib/Verify/Backend/Certify.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clang/lib/Verify/Backend/Certify.cpp b/clang/lib/Verify/Backend/Certify.cpp index 66a8254347..280b570e84 100644 --- a/clang/lib/Verify/Backend/Certify.cpp +++ b/clang/lib/Verify/Backend/Certify.cpp @@ -4187,8 +4187,10 @@ verify::candidateValues(const ObligationModule &Module, const LogicExpr &Query, It != Module.DiagnosticVariables.end() ? It->second.DisplayName : Name; Value.InternalName = Name; Value.Sort = Sort; - if (It != Module.DiagnosticVariables.end()) + if (It != Module.DiagnosticVariables.end()) { Value.Source = It->second.Source; + Value.Reference = It->second.Reference; + } if (std::optional Given = Model.constant(Name, Sort)) Value.Value = formatLogicValue(*Given); Values.push_back(std::move(Value)); From 86da1bdd8a8f7d4fe541fd88d9cbf514d6f64519 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:24 +0530 Subject: [PATCH 026/259] verify: Let a caller collect results as diagnostic parts. --- clang/lib/Verify/Driver/Verifier.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/clang/lib/Verify/Driver/Verifier.h b/clang/lib/Verify/Driver/Verifier.h index 4144be1306..06ae6ee687 100644 --- a/clang/lib/Verify/Driver/Verifier.h +++ b/clang/lib/Verify/Driver/Verifier.h @@ -3,6 +3,7 @@ #define LLVM_CLANG_VERIFY_DRIVER_VERIFIER_H #include "../Backend/VerifyBackend.h" +#include "DiagnosticPart.h" #include "llvm/Support/raw_ostream.h" #include #include @@ -128,6 +129,9 @@ struct VerifyOptions { unsigned ConfirmBound = 10; /// Where the run counts the verdicts it prints, if anywhere. VerifySummary *Summary = nullptr; + /// Where to put each result as Clang diagnostics instead of printing it, + /// for the compile path to report through the compiler's own engine. + std::vector *Parts = nullptr; /// A run over several files, which holds each file's results until every /// file is verified (see CrossFileRun), or null. class CrossFileRun *CrossFile = nullptr; From 486bc85f4d3bd84a035ad4e74e0ef1612a6dbc5b Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:24 +0530 Subject: [PATCH 027/259] verify: Print verification results as Clang diagnostics. --- clang/lib/Verify/Driver/Verifier.cpp | 287 ++++++++++++++++++--------- 1 file changed, 190 insertions(+), 97 deletions(-) diff --git a/clang/lib/Verify/Driver/Verifier.cpp b/clang/lib/Verify/Driver/Verifier.cpp index 5b4be1d8c7..43d0ce7f46 100644 --- a/clang/lib/Verify/Driver/Verifier.cpp +++ b/clang/lib/Verify/Driver/Verifier.cpp @@ -23,6 +23,7 @@ #include "../Transform/Passivize.h" #include "../Transform/SpecInline.h" #include "../Transform/UBChecks.h" +#include "Counterexample.h" #include "CppVerifyVersion.h" #include "DumpIR.h" #include "LeanAutomation.h" @@ -847,6 +848,7 @@ std::optional confirmCounterexample( Item.StableId = Like.StableId; Item.Kind = Like.Kind; Item.Loc = Like.Loc; + Item.BeginLoc = Like.BeginLoc; Item.EndLoc = Like.EndLoc; Item.Source = Like.Source; Item.Goal = std::move(Goal); @@ -900,19 +902,11 @@ std::optional confirmCounterexample( for (const VerifyModelValue &Value : R.Unchecked) if (Fixed.count(Value.InternalName)) Failed.Model.push_back(Value); - std::string Message; - for (const VerifyModelValue &Value : Failed.Model) { - Message += (Message.empty() ? "" : ", ") + Value.DisplayName; - if (Value.DisplayName != Value.InternalName) - Message += " [ssa=" + Value.InternalName + "]"; - Message += " [type=" + formatLogicSort(Value.Sort) + "] = " + *Value.Value; - } std::string Using; for (const std::string &Identity : Contracts) if (auto It = Functions.find(Identity); It != Functions.end()) Using += (Using.empty() ? "" : ", ") + It->second->Name; Failed.Message = - Message + (Message.empty() ? "" : "; ") + "confirmed by a proof at this input" + (Using.empty() ? std::string() : " that uses the contract of " + Using) + ", since its check could not compute " + R.UncheckedApplication; @@ -1162,6 +1156,9 @@ struct VerifyDiagnostic { /// For an error about source the verifier cannot represent: that source, /// shown with its line as a compiler error is. SourceRange Span; + /// The declaration of the function the result is about, where a compiler + /// remark about a proof points. + SourceLocation FunctionLoc; /// A spec function that needs no check, listed with --verbose: no verdict. bool Axiom = false; /// What else the verifier found about the verdict, each printed as a note. @@ -1180,6 +1177,14 @@ static uint64_t nanosecondsSince(std::chrono::steady_clock::time_point Start) { .count(); } +/// The kind of check a failure is, "[postcondition]"; its location is the +/// diagnostic's, and JSON keeps the stable obligation ID. +static std::string obligationTag(const VerifyResult &Result) { + if (Result.ObligationType) + return std::string(" [") + obligationKindName(*Result.ObligationType) + "]"; + return Result.ObligationId.empty() ? "" : " [" + Result.ObligationId + "]"; +} + static std::string backendSuffix(const VerifyResult &Result) { std::string Suffix; if (!Result.BackendName.empty()) { @@ -3748,9 +3753,10 @@ class Verifier { (Bound == 0 ? std::string("with no iteration of any loop") : "within " + iterations(Bound) + " of each loop") + - (Result.Message.empty() + (counterexampleText(Result).empty() ? std::string() - : " (counterexample: " + Result.Message + ")")); + : " (counterexample: " + counterexampleText(Result) + + ")")); return Notes; } CopiesHold &= Result.Status == VerifyStatus::Verified; @@ -3925,11 +3931,10 @@ class Verifier { Interface.Name, R}); Run.ContractCheck = Diags.size() - 1; } else if (R.Status == VerifyStatus::Failed) { - std::string Message = "verification failed: " + Label; - if (!R.ObligationId.empty()) - Message += " [" + R.ObligationId + "]"; + std::string Message = + "verification failed: " + Label + obligationTag(R); if (!R.Message.empty()) - Message += " (counterexample: " + R.Message + ")"; + Message += " (" + R.Message + ")"; Message += backendSuffix(R); unsettled(VerifyDiagnostic::Error, std::move(Message), R); } else { @@ -4982,11 +4987,10 @@ class Verifier { // The failure, and those after it --max-failures reports, each // with its counterexample and notes. auto failure = [&](const VerifyResult &Failure) { - std::string Msg = "verification failed: " + Fn->Name; - if (!Failure.ObligationId.empty()) - Msg += " [" + Failure.ObligationId + "]"; + std::string Msg = + "verification failed: " + Fn->Name + obligationTag(Failure); if (!Failure.Message.empty()) - Msg += " (counterexample: " + Failure.Message + ")"; + Msg += " (" + Failure.Message + ")"; Msg += backendSuffix(Failure); Diags.push_back({VerifyDiagnostic::Error, Msg, Failure.Location, Fn->Name, Failure}); @@ -5139,6 +5143,7 @@ class Verifier { // What a function --function leaves out reports stays, hidden, for // what it establishes. D.Hidden |= !Selected[I]; + D.FunctionLoc = Functions[I]->DeclLoc; Diags.push_back(std::move(D)); } AllOk &= Run.AllOk; @@ -5855,11 +5860,9 @@ class Verifier { VerifyResult &Failed = *Outcomes[I]; std::string Message; if (Pending.Label == "verification") { - Message = "verification failed: " + Pending.Fn->Name; - if (!Failed.ObligationId.empty()) - Message += " [" + Failed.ObligationId + "]"; - Message += " (counterexample: " + Failed.Message + ")" + - backendSuffix(Failed); + Message = "verification failed: " + Pending.Fn->Name + + obligationTag(Failed) + " (" + Failed.Message + ")" + + backendSuffix(Failed); } else { Message = Pending.Label + " failed: " + Pending.Fn->Name + backendSuffix(Failed) + " (" + Failed.Message + ")"; @@ -6241,6 +6244,8 @@ class Verifier { : llvm::json::Value(nullptr); if (Value.Source.isValid()) Entry["source"] = sourceJSON(Value.Source); + if (Value.OnPath == false) + Entry["on_path"] = false; Model.push_back(std::move(Entry)); } Record["model"] = std::move(Model); @@ -6488,8 +6493,16 @@ class Verifier { continue; if (Opts.Summary) count(D, *Opts.Summary); - if (!quieted(D)) + if (quieted(D)) + continue; + if (Opts.Parts) { + std::vector Parts = partsOf(D); + if (Parts.front().Loc.isInvalid()) + Parts.front().Loc = D.FunctionLoc; + Opts.Parts->insert(Opts.Parts->end(), Parts.begin(), Parts.end()); + } else { printDiagnostic(D, OS); + } } } @@ -6564,94 +6577,174 @@ class Verifier { return Report; } - void printDiagnostic(const VerifyDiagnostic &D, llvm::raw_ostream &OS) const { - if (Opts.Diagnostics == DiagnosticFormat::Json) { - printJSONDiagnostic(D, OS); - return; - } - const std::pair *Instantiation = - instantiationOf(D); - const std::string InstantiationNote = - Instantiation ? "in instantiation of " + Instantiation->second + " '" + - D.FunctionName + "' requested here" - : std::string(); - if (D.K == VerifyDiagnostic::Error && D.Span.isValid()) { - DiagnosticOptions DiagOpts; - DiagOpts.ShowPresumedLoc = true; - TextDiagnostic Text(OS, Ctx.getLangOpts(), DiagOpts); - Text.emitDiagnostic( - FullSourceLoc(D.Span.getBegin(), Ctx.getSourceManager()), - DiagnosticsEngine::Error, D.Message, - CharSourceRange::getTokenRange(D.Span), {}); - if (Instantiation) - Text.emitDiagnostic( - FullSourceLoc(Instantiation->first, Ctx.getSourceManager()), - DiagnosticsEngine::Note, InstantiationNote, {}, {}); - return; + /// An error as Clang diagnostics: the error at the failing source, with + /// its range; for a counterexample, its values in source names and each + /// step of its path at its location; then the error's notes. + std::vector + errorParts(const VerifyDiagnostic &D) const { + std::vector Parts; + VerifyDiagnosticPart Error; + Error.Level = DiagnosticsEngine::Error; + Error.Message = D.Message; + if (D.Span.isValid()) { + Error.Loc = D.Span.getBegin(); + Error.Range = D.Span; + } else { + Error.Loc = D.Loc; + // An obligation's range underlines its expression, the caret at its + // operator, when the expression lies on the caret's line; one that runs + // to another line (a spec's post through to its return) is not shown. + const SourceManager &SM = Ctx.getSourceManager(); + auto onCaretLine = [&](SourceLocation Loc) { + return Loc.isValid() && SM.isWrittenInSameFile(D.Loc, Loc) && + SM.getSpellingLineNumber(D.Loc) == SM.getSpellingLineNumber(Loc); + }; + if (D.Result && D.Result->Location == D.Loc) { + SourceLocation Begin = D.Result->BeginLocation; + SourceLocation End = D.Result->EndLocation; + if (!onCaretLine(Begin) || SM.isBeforeInTranslationUnit(D.Loc, Begin)) + Begin = D.Loc; + if (onCaretLine(End) && !SM.isBeforeInTranslationUnit(End, D.Loc) && + (Begin != D.Loc || End != D.Loc)) + Error.Range = SourceRange(Begin, End); + } } - if (D.Loc.isValid()) { - PresumedLoc PLoc = Ctx.getSourceManager().getPresumedLoc(D.Loc); - if (PLoc.isValid()) - OS << PLoc.getFilename() << ":" << PLoc.getLine() << ":" - << PLoc.getColumn() << ": "; + Parts.push_back(Error); + // A step inside a macro is shown where the macro is used: the error + // already shows the expansion, and each note would repeat it. + auto note = [&](SourceLocation Loc, std::string Message) { + if (Loc.isMacroID()) + Loc = Ctx.getSourceManager().getExpansionLoc(Loc); + Parts.push_back({DiagnosticsEngine::Note, Loc, {}, std::move(Message)}); + }; + if (D.Result && D.Result->Status == VerifyStatus::Failed) { + const VerifyResult &R = *D.Result; + if (std::string Values = counterexampleText(R); !Values.empty()) + note(Error.Loc, "counterexample: " + Values); + const size_t Steps = R.Trace.size(); + for (size_t I = 0; I != Steps; ++I) { + if (Steps > TraceStepLimit && I == TraceStepLimit / 2) + note({}, "(skipping " + std::to_string(Steps - TraceStepLimit) + + " steps of the path; JSON lists every one)"); + if (Steps > TraceStepLimit && I >= TraceStepLimit / 2 && + I < Steps - TraceStepLimit / 2) + continue; + note(R.Trace[I].Loc, traceStepText(R.Trace[I])); + } } + if (const auto *Instantiation = instantiationOf(D)) + note(Instantiation->first, "in instantiation of " + + Instantiation->second + " '" + + D.FunctionName + "' requested here"); + for (const std::string &Note : D.Notes) + note({}, Note); + return Parts; + } + + /// The line a result prints, apart from its location: "Verified: f". + std::string statusLine(const VerifyDiagnostic &D) const { switch (D.K) { case VerifyDiagnostic::Lowered: - OS << "Lowered: " << D.Message << "\n"; - break; + return "Lowered: " + D.Message; case VerifyDiagnostic::Verified: - OS << "Verified: " << D.Message << "\n"; - break; + return "Verified: " + D.Message; case VerifyDiagnostic::Error: - OS << "error: " << D.Message << "\n"; - break; + case VerifyDiagnostic::Warning: + return D.Message; case VerifyDiagnostic::Unresolved: - OS << "Unresolved: " << D.Message << "\n"; - if (D.Result) - for (const QuantifierProfileEntry &Entry : D.Result->QuantifierProfile) - OS << "note: the quantifier at " << Entry.Line << ":" << Entry.Column - << " was instantiated " << Entry.Instances - << " times, up to generation " << Entry.MaxGeneration << "\n"; - break; + return "Unresolved: " + D.Message; case VerifyDiagnostic::Interrupted: - OS << "Interrupted: " << D.Message << "\n"; - break; + return "Interrupted: " + D.Message; case VerifyDiagnostic::BoundedSafe: - OS << "BoundedSafe: " << D.Message << "\n"; - break; - case VerifyDiagnostic::Exported: - OS << "Exported: " << D.Message; + return "BoundedSafe: " + D.Message; + case VerifyDiagnostic::Exported: { + std::string Line = "Exported: " + D.Message; if (D.LeanAutomatic && D.Result) - OS << " (cppverify_auto proved " << D.LeanAutomatic << " of " - << std::set(D.Result->LeanGoals.begin(), - D.Result->LeanGoals.end()) - .size() - << " goals)"; - OS << "\n"; - break; + Line += + " (cppverify_auto proved " + std::to_string(D.LeanAutomatic) + + " of " + + std::to_string(std::set(D.Result->LeanGoals.begin(), + D.Result->LeanGoals.end()) + .size()) + + " goals)"; + return Line; + } case VerifyDiagnostic::Certified: - OS << "Certified: " << D.Message << "\n"; - break; + return "Certified: " + D.Message; case VerifyDiagnostic::MixedProof: - OS << "Proved (" << D.Result->BackendName << "): " << D.Message << "\n"; - break; + return "Proved (" + D.Result->BackendName + "): " + D.Message; case VerifyDiagnostic::Trusted: - OS << "Trusted: " << D.Message << "\n"; - break; - case VerifyDiagnostic::Warning: - OS << "warning: " << D.Message << "\n"; - break; - } - if (Instantiation) { - PresumedLoc PLoc = - Ctx.getSourceManager().getPresumedLoc(Instantiation->first); - if (PLoc.isValid()) - OS << PLoc.getFilename() << ":" << PLoc.getLine() << ":" - << PLoc.getColumn() << ": "; - OS << "note: " << InstantiationNote << "\n"; + return "Trusted: " + D.Message; } + return D.Message; + } + + /// A result as Clang diagnostics: an error with its counterexample, a + /// warning, or a status line (an error when unresolved, else a remark), + /// each followed by its notes. + std::vector partsOf(const VerifyDiagnostic &D) const { + if (D.K == VerifyDiagnostic::Error) + return errorParts(D); + std::vector Parts; + DiagnosticsEngine::Level Level = DiagnosticsEngine::Remark; + if (D.K == VerifyDiagnostic::Warning) + Level = DiagnosticsEngine::Warning; + else if (D.K == VerifyDiagnostic::Unresolved || + D.K == VerifyDiagnostic::Interrupted) + Level = DiagnosticsEngine::Error; + Parts.push_back({Level, D.Loc, {}, statusLine(D)}); + auto note = [&](SourceLocation Loc, std::string Message) { + Parts.push_back({DiagnosticsEngine::Note, Loc, {}, std::move(Message)}); + }; + if (D.K == VerifyDiagnostic::Unresolved && D.Result) + for (const QuantifierProfileEntry &Entry : D.Result->QuantifierProfile) + note({}, "the quantifier at " + std::to_string(Entry.Line) + ":" + + std::to_string(Entry.Column) + " was instantiated " + + std::to_string(Entry.Instances) + + " times, up to generation " + + std::to_string(Entry.MaxGeneration)); + if (const auto *Instantiation = instantiationOf(D)) + note(Instantiation->first, "in instantiation of " + + Instantiation->second + " '" + + D.FunctionName + "' requested here"); for (const std::string &Note : D.Notes) - OS << "note: " << Note << "\n"; + note({}, Note); + return Parts; + } + + /// Errors and warnings print as Clang prints its diagnostics, with the + /// source they are about; other results as their status line. + void printDiagnostic(const VerifyDiagnostic &D, llvm::raw_ostream &OS) const { + if (Opts.Diagnostics == DiagnosticFormat::Json) { + printJSONDiagnostic(D, OS); + return; + } + const std::vector Parts = partsOf(D); + if (D.K == VerifyDiagnostic::Error || D.K == VerifyDiagnostic::Warning) { + DiagnosticOptions DiagOpts; + DiagOpts.ShowPresumedLoc = true; + TextDiagnostic Text(OS, Ctx.getLangOpts(), DiagOpts); + for (const VerifyDiagnosticPart &Part : Parts) { + llvm::SmallVector Ranges; + if (Part.Range.isValid()) + Ranges.push_back(CharSourceRange::getTokenRange(Part.Range)); + Text.emitDiagnostic( + Part.Loc.isValid() ? FullSourceLoc(Part.Loc, Ctx.getSourceManager()) + : FullSourceLoc(), + Part.Level, Part.Message, Ranges, {}); + } + return; + } + for (const VerifyDiagnosticPart &Part : Parts) { + if (Part.Loc.isValid()) { + PresumedLoc PLoc = Ctx.getSourceManager().getPresumedLoc(Part.Loc); + if (PLoc.isValid()) + OS << PLoc.getFilename() << ":" << PLoc.getLine() << ":" + << PLoc.getColumn() << ": "; + } + OS << (Part.Level == DiagnosticsEngine::Note ? "note: " : "") + << Part.Message << "\n"; + } } }; From 407849b2df85ce8ab8b2356943cfd8c0219a6e11 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:25 +0530 Subject: [PATCH 028/259] verify: Return verification results to the compiler as diagnostic parts. --- clang/lib/Verify/Driver/CppVerifyIntegration.h | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/clang/lib/Verify/Driver/CppVerifyIntegration.h b/clang/lib/Verify/Driver/CppVerifyIntegration.h index bfee19996e..8d7ec4f770 100644 --- a/clang/lib/Verify/Driver/CppVerifyIntegration.h +++ b/clang/lib/Verify/Driver/CppVerifyIntegration.h @@ -2,9 +2,10 @@ #ifndef LLVM_CLANG_VERIFY_DRIVER_CPPVERIFY_INTEGRATION_H #define LLVM_CLANG_VERIFY_DRIVER_CPPVERIFY_INTEGRATION_H +#include "DiagnosticPart.h" #include #include -#include +#include namespace clang { class ASTContext; @@ -12,7 +13,11 @@ class CompilerInstance; namespace verify { -using CppVerifyAsyncResult = std::pair; +/// Whether verification succeeded, and its results as Clang diagnostics. +struct CppVerifyAsyncResult { + bool Ok = false; + std::vector Parts; +}; /// Returns true if CppVerify SMT should run for this compilation. bool shouldRunCppVerify(const CompilerInstance &CI); @@ -24,7 +29,9 @@ bool shouldRunCppVerify(const CompilerInstance &CI); std::future startCppVerifyAsync(ASTContext &Ctx, std::string ContractsOut = ""); -/// Join \p Future, print verifier output, and report diagnostics on failure. +/// Join \p Future and report its results through the compiler's diagnostics: +/// failures as errors with notes, warnings in -Wcppverify, and proofs as +/// remarks (-Rcppverify). bool finishCppVerify(CompilerInstance &CI, std::future Future); } // namespace verify From 3b8b67fc5cb6d3e69db55c84c0cb6ae1507eba3d Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:25 +0530 Subject: [PATCH 029/259] verify: Report compile-time verification results through the diagnostics engine. --- .../Verify/Driver/CppVerifyIntegration.cpp | 44 ++++++++++++++----- 1 file changed, 32 insertions(+), 12 deletions(-) diff --git a/clang/lib/Verify/Driver/CppVerifyIntegration.cpp b/clang/lib/Verify/Driver/CppVerifyIntegration.cpp index 497bcfe7c3..b664448748 100644 --- a/clang/lib/Verify/Driver/CppVerifyIntegration.cpp +++ b/clang/lib/Verify/Driver/CppVerifyIntegration.cpp @@ -22,25 +22,45 @@ bool verify::shouldRunCppVerify(const CompilerInstance &CI) { std::future verify::startCppVerifyAsync(ASTContext &Ctx, std::string ContractsOut) { return std::async(std::launch::async, [&Ctx, ContractsOut]() { - std::string Buffer; - llvm::raw_string_ostream OS(Buffer); + CppVerifyAsyncResult Result; VerifyOptions Opts; Opts.ContractsOut = ContractsOut; - bool Ok = verifyTranslationUnit(Ctx, OS, Opts); - OS.flush(); - return CppVerifyAsyncResult{Ok, std::move(Buffer)}; + Opts.Parts = &Result.Parts; + Result.Ok = verifyTranslationUnit(Ctx, llvm::nulls(), Opts); + return Result; }); } bool verify::finishCppVerify(CompilerInstance &CI, std::future Future) { CppVerifyAsyncResult R = Future.get(); - if (!R.second.empty()) - llvm::errs() << R.second; - if (!R.first) { - CI.getDiagnostics().Report(diag::err_fe_cppverify_failed) - << "verification failed"; - return false; + DiagnosticsEngine &Diags = CI.getDiagnostics(); + bool Reported = false; + for (const VerifyDiagnosticPart &Part : R.Parts) { + unsigned ID = diag::note_cppverify_result; + switch (Part.Level) { + case DiagnosticsEngine::Error: + case DiagnosticsEngine::Fatal: + ID = diag::err_cppverify_result; + Reported = true; + break; + case DiagnosticsEngine::Warning: + ID = diag::warn_cppverify_result; + break; + case DiagnosticsEngine::Remark: + ID = diag::remark_cppverify_result; + break; + case DiagnosticsEngine::Note: + case DiagnosticsEngine::Ignored: + break; + } + DiagnosticBuilder Builder = Diags.Report(Part.Loc, ID); + Builder << Part.Message; + if (Part.Range.isValid()) + Builder << CharSourceRange::getTokenRange(Part.Range); } - return true; + // A failure without a result of its own still fails the compilation. + if (!R.Ok && !Reported) + Diags.Report(diag::err_fe_cppverify_failed) << "verification failed"; + return R.Ok; } \ No newline at end of file From f892938e7c41df6739e284ff2e25dffe8589e35b Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:26 +0530 Subject: [PATCH 030/259] verify: Print replayed failures with their counterexample and path notes. --- clang/tools/cpp-verify/Main.cpp | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/clang/tools/cpp-verify/Main.cpp b/clang/tools/cpp-verify/Main.cpp index 50257ca374..aeed96c9c3 100644 --- a/clang/tools/cpp-verify/Main.cpp +++ b/clang/tools/cpp-verify/Main.cpp @@ -4,6 +4,7 @@ #include "../../lib/Verify/Backend/ObligationSimplify.h" #include "../../lib/Verify/Backend/ProofCache.h" #include "../../lib/Verify/Backend/VerifyBackend.h" +#include "Counterexample.h" #include "CppVerifyVersion.h" #include "DumpIR.h" #include "Verifier.h" @@ -1020,11 +1021,24 @@ static int replayObligationArchive() { AllOk = false; printResultSource(); llvm::outs() << "error: verification failed: " << Module.FunctionName; - if (!Result.ObligationId.empty()) + if (Result.ObligationType) + llvm::outs() << " [" + << verify::obligationKindName(*Result.ObligationType) + << "]"; + else if (!Result.ObligationId.empty()) llvm::outs() << " [" << Result.ObligationId << "]"; if (!Result.Message.empty()) - llvm::outs() << " (counterexample: " << Result.Message << ")"; + llvm::outs() << " (" << Result.Message << ")"; llvm::outs() << Suffix << "\n"; + if (std::string Values = verify::counterexampleText(Result); + !Values.empty()) + llvm::outs() << "note: counterexample: " << Values << "\n"; + for (const verify::VerifyTraceEvent &Event : Result.Trace) { + if (Event.Source.isValid()) + llvm::outs() << Event.Source.File << ":" << Event.Source.Line << ":" + << Event.Source.Column << ": "; + llvm::outs() << "note: " << verify::traceStepText(Event) << "\n"; + } break; case verify::VerifyStatus::Unresolved: AllOk = false; From 7543831c2ee168eb47e96e5051e3163c58ada9dd Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:26 +0530 Subject: [PATCH 031/259] test: Check the verification results a compilation reports. --- clang/test/Verify/compile_diagnostics.cpp | 81 +++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 clang/test/Verify/compile_diagnostics.cpp diff --git a/clang/test/Verify/compile_diagnostics.cpp b/clang/test/Verify/compile_diagnostics.cpp new file mode 100644 index 0000000000..4d710f2c87 --- /dev/null +++ b/clang/test/Verify/compile_diagnostics.cpp @@ -0,0 +1,81 @@ +// RUN: not %clang -std=c++17 -fverify-contracts -c -o %t.o %s 2>&1 | FileCheck %s --implicit-check-not=remark: +// RUN: not %clang -std=c++17 -fverify-contracts -Rcppverify -c -o %t.o %s 2>&1 | FileCheck %s --check-prefixes=CHECK,REMARK +// RUN: not %clang -std=c++17 -fverify-contracts -Wno-cppverify -c -o %t.o %s 2>&1 | FileCheck %s --check-prefix=QUIET +// RUN: not %clang -std=c++17 -fverify-contracts -Werror=cppverify -c -o %t.o %s 2>&1 | FileCheck %s --check-prefix=WERROR +// RUN: not %clang -std=c++17 -fverify-contracts -fdiagnostics-format=sarif -Wno-sarif-format-unstable -c -o %t.o %s 2>&1 | FileCheck %s --check-prefix=SARIF +// RUN: %clang -std=c++17 -fverify-contracts -fno-verify -c -o %t.o %s 2>&1 | count 0 +// +// A compilation with -fverify-contracts reports each result as a diagnostic +// of the compiler: a failure is an error at the failing check, its +// expression underlined, with its counterexample and path as notes; an +// unresolved result is an error; a warning belongs to -Wcppverify; a proof +// is a remark of -Rcppverify at its function, shown only when asked for. + +namespace cv = cppverify; + +int inc(int x) + cv::pre(x < 100) + cv::post(cv::result == x + 1) +{ + return x + 1; +} +// REMARK: compile_diagnostics.cpp:[[@LINE-6]]:5: remark: Verified: inc [backend=z3] [-Rcppverify] + +int clamp(int x) + cv::post(cv::result >= 0) +{ + if (x < 0) + return x + 1; + return x; +} +// CHECK: compile_diagnostics.cpp:[[@LINE-6]]:23: error: verification failed: clamp [postcondition] [backend=z3] [reason=counterexample] +// CHECK-NEXT: [[@LINE-7]] | cv::post(cv::result >= 0) +// CHECK-NEXT: | ~~~~~~~~~~~^~~~ +// CHECK-NEXT: compile_diagnostics.cpp:[[@LINE-9]]:23: note: counterexample: x = {{-[0-9]+}}, result = {{-?[0-9]+}} +// CHECK-NEXT: compile_diagnostics.cpp:[[@LINE-8]]:3: note: takes the true branch +// CHECK: compile_diagnostics.cpp:[[@LINE-8]]:5: note: returns {{-?[0-9]+}} + +int never(int x) + cv::pre(x > 0 && x < 0) + cv::post(cv::result == 1) +{ + return 0; +} +// REMARK: compile_diagnostics.cpp:[[@LINE-6]]:5: remark: Verified: never [backend=z3] [vacuous] [-Rcppverify] +// CHECK: compile_diagnostics.cpp:[[@LINE-7]]:5: warning: never: the precondition is unsatisfiable, so every claim about it holds vacuously [-Wcppverify] +// WERROR: compile_diagnostics.cpp:[[@LINE-8]]:5: error: never: the precondition is unsatisfiable, so every claim about it holds vacuously [-Werror,-Wcppverify] + +int unmeasured(int n) + cv::pre(n >= 0) + cv::post(cv::result == n) +{ + int i = 0; + while (i < n) + cv::invariant(i <= n) + { + i = i + 1; + } + return i; +} +// CHECK: compile_diagnostics.cpp:[[@LINE-7]]:3: error: Unresolved: unmeasured [backend=z3] [reason=decreases.missing] +// CHECK: 1 warning and 2 errors generated. + +// QUIET-NOT: warning: +// QUIET: error: verification failed: clamp +// QUIET-NOT: warning: +// QUIET: error: Unresolved: unmeasured +// QUIET-NOT: warning: +// QUIET: 2 errors generated. + +// WERROR: 3 errors generated. + +// SARIF: "level": "error", +// SARIF: "ruleId": "err_cppverify_result" +// SARIF: "level": "note", +// SARIF: "text": "counterexample: x = {{-[0-9]+}}, result = {{-?[0-9]+}}" +// SARIF: "ruleId": "note_cppverify_result" +// SARIF: "level": "warning", +// SARIF: "text": "never: the precondition is unsatisfiable, so every claim about it holds vacuously" +// SARIF: "ruleId": "warn_cppverify_result" +// SARIF: "text": "Unresolved: unmeasured [backend=z3] [reason=decreases.missing] +// SARIF: "ruleId": "err_cppverify_result" From 7dd7665fdba71baf72c8f49cdf2895f7d645598d Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:27 +0530 Subject: [PATCH 032/259] test: Check the range, counterexample, and path notes of a failure. --- clang/test/Verify/suite/failure_notes.cpp | 305 ++++++++++++++++++++++ 1 file changed, 305 insertions(+) create mode 100644 clang/test/Verify/suite/failure_notes.cpp diff --git a/clang/test/Verify/suite/failure_notes.cpp b/clang/test/Verify/suite/failure_notes.cpp new file mode 100644 index 0000000000..91f99eca89 --- /dev/null +++ b/clang/test/Verify/suite/failure_notes.cpp @@ -0,0 +1,305 @@ +// RUN: not %cpp-verify --jobs=1 %s -- 2>&1 | FileCheck %s --strict-whitespace +// RUN: not %cpp-verify --jobs=1 --backend=bmc --unroll=3 %s -- 2>&1 | FileCheck %s --check-prefix=BMC +// RUN: not %cpp-verify --jobs=1 --diagnostics-format=json %s -- 2>/dev/null | FileCheck %s --check-prefix=JSON +// RUN: not %cpp-verify --jobs=1 --obligation-out=%t.cpv %s -- > /dev/null 2>&1 +// RUN: not %cpp-verify --obligation-in=%t.cpv 2>&1 | FileCheck %s --check-prefix=REPLAY +// +// A failure is a Clang error at the failing check, its expression +// underlined with the caret at its operator when it lies on one line (a +// caret alone otherwise); its counterexample, each variable once with the +// values it takes along the path, and not those of branches the path does +// not take; and each step of the path at its line, in the words of Clang's +// static analyzer. A path of more than ten steps shows its first and last +// five. A step inside a macro is shown where the macro is used, and an +// operation whose own check fails is no step of the path. + +namespace cv = cppverify; + +int steps(int x) + cv::pre(0 <= x && x <= 10) + cv::post(cv::result < 3) +{ + int y = 0; + if (x > 4) + y = y + 1; + else + y = y + 2; + if (x > 8) + y = y + 3; + return y; +} +// CHECK: {{.*}}failure_notes.cpp:[[@LINE-11]]:23: error: verification failed: steps [postcondition] [backend=z3] [reason=counterexample] +// CHECK-NEXT: {{^ *}}[[@LINE-12]] | cv::post(cv::result < 3){{$}} +// CHECK-NEXT: {{^}} | ~~~~~~~~~~~^~~{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-14]]:23: note: counterexample: x = {{9|10}}, y = 0 -> 1 -> 4, result = 4 +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-12]]:3: note: takes the true branch +// CHECK-NEXT: {{^ *}}[[@LINE-13]] | if (x > 4){{$}} +// CHECK-NEXT: {{^}} | ^{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-11]]:3: note: takes the true branch +// CHECK-NEXT: {{^ *}}[[@LINE-12]] | if (x > 8){{$}} +// CHECK-NEXT: {{^}} | ^{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-12]]:3: note: returns 4 +// CHECK-NEXT: {{^ *}}[[@LINE-13]] | return y;{{$}} +// CHECK-NEXT: {{^}} | ^{{$}} + +int add(int a) + cv::pre(a < 100) + cv::post(cv::result == a + 1) +{ + return a + 1; +} + +int calls(int x) + cv::pre(0 <= x && x < 50) + cv::post(cv::result < 10) +{ + return add(x); +} +// CHECK: {{.*}}failure_notes.cpp:[[@LINE-4]]:23: error: verification failed: calls [postcondition] [backend=z3] [reason=counterexample] +// CHECK-NEXT: {{^ *}}[[@LINE-5]] | cv::post(cv::result < 10){{$}} +// CHECK-NEXT: {{^}} | ~~~~~~~~~~~^~~~{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-7]]:23: note: counterexample: x = [[X:[0-9]+]], result = {{[0-9]+}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-6]]:3: note: calls add([[X]]) +// CHECK-NEXT: {{^ *}}[[@LINE-7]] | return add(x);{{$}} +// CHECK-NEXT: {{^}} | ^{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-9]]:3: note: returns {{[0-9]+}} + + +void store(int *p, int v) + cv::pre(p != nullptr) + cv::modifies(*p) + cv::post(*p == 7) +{ + *p = v; +} +// CHECK: {{.*}}failure_notes.cpp:[[@LINE-4]]:15: error: verification failed: store [postcondition] [backend=z3] [reason=counterexample] +// CHECK-NEXT: {{^ *}}[[@LINE-5]] | cv::post(*p == 7){{$}} +// CHECK-NEXT: {{^}} | ~~~^~~~{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-7]]:15: note: counterexample: p = [[P:[0-9]+]], v = [[V:-?[0-9]+]] +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-6]]:6: note: stores [[V]] at address [[P]] +// CHECK-NEXT: {{^ *}}[[@LINE-7]] | *p = v;{{$}} +// CHECK-NEXT: {{^}} | ^{{$}} + +int heap(int v) + cv::post(cv::result == 1) +{ + int *p = new int(v); + int r = *p; + delete p; + return r; +} +// CHECK: {{.*}}failure_notes.cpp:[[@LINE-7]]:23: error: verification failed: heap [postcondition] [backend=z3] [reason=counterexample] +// CHECK-NEXT: {{^ *}}[[@LINE-8]] | cv::post(cv::result == 1){{$}} +// CHECK-NEXT: {{^}} | ~~~~~~~~~~~^~~~{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-10]]:23: note: counterexample: v = [[V:-?[0-9]+]], p = [[P:[0-9]+]], r = [[V]], result = [[V]] +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-9]]:3: note: allocates an object at address [[P]] +// CHECK-NEXT: {{^ *}}[[@LINE-10]] | int *p = new int(v);{{$}} +// CHECK-NEXT: {{^}} | ^{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-10]]:3: note: deletes the object at address [[P]] +// CHECK-NEXT: {{^ *}}[[@LINE-11]] | delete p;{{$}} +// CHECK-NEXT: {{^}} | ^{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-12]]:3: note: returns [[V]] +// CHECK-NEXT: {{^ *}}[[@LINE-13]] | return r;{{$}} +// CHECK-NEXT: {{^}} | ^{{$}} + +int local(int v) + cv::pre(0 <= v && v < 100) + cv::post(cv::result == 1) +{ + int a = v; + int &r = a; + r = r + 1; + return a; +} +// CHECK: {{.*}}failure_notes.cpp:[[@LINE-7]]:23: error: verification failed: local [postcondition] [backend=z3] [reason=counterexample] +// CHECK-NEXT: {{^ *}}[[@LINE-8]] | cv::post(cv::result == 1){{$}} +// CHECK-NEXT: {{^}} | ~~~~~~~~~~~^~~~{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-10]]:23: note: counterexample: v = [[V:[0-9]+]], &r = [[A:[0-9]+]], result = [[R:[0-9]+]] +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-9]]:3: note: creates a local object at address [[A]] +// CHECK-NEXT: {{^ *}}[[@LINE-10]] | int a = v;{{$}} +// CHECK-NEXT: {{^}} | ^{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-10]]:5: note: stores [[R]] at address [[A]] +// CHECK-NEXT: {{^ *}}[[@LINE-11]] | r = r + 1;{{$}} +// CHECK-NEXT: {{^}} | ^{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-12]]:3: note: returns [[R]] +// CHECK-NEXT: {{^ *}}[[@LINE-13]] | return a;{{$}} +// CHECK-NEXT: {{^}} | ^{{$}} + +int scoped(int v) + cv::pre(2 <= v && v < 100) + cv::post(cv::result == 1) +{ + int s = 0; + { + int a = v; + int &r = a; + s = r; + } + return s; +} +// CHECK: {{.*}}failure_notes.cpp:[[@LINE-10]]:23: error: verification failed: scoped [postcondition] [backend=z3] [reason=counterexample] +// CHECK-NEXT: {{^ *}}[[@LINE-11]] | cv::post(cv::result == 1){{$}} +// CHECK-NEXT: {{^}} | ~~~~~~~~~~~^~~~{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-13]]:23: note: counterexample: v = [[V:[0-9]+]], s = 0 -> [[V]], &r = [[A:[0-9]+]], result = [[V]] +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-10]]:5: note: creates a local object at address [[A]] +// CHECK-NEXT: {{^ *}}[[@LINE-11]] | int a = v;{{$}} +// CHECK-NEXT: {{^}} | ^{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-10]]:3: note: ends the lifetime of a local object +// CHECK-NEXT: {{^ *}}[[@LINE-11]] | }{{$}} +// CHECK-NEXT: {{^}} | ^{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-12]]:3: note: returns [[V]] +// CHECK-NEXT: {{^ *}}[[@LINE-13]] | return s;{{$}} +// CHECK-NEXT: {{^}} | ^{{$}} + +int loop(int n) + cv::pre(0 <= n && n <= 5) + cv::post(cv::result == 0) +{ + int i = 0; + while (i < n) + cv::invariant(0 <= i && i <= n) + cv::decreases(n - i) + { + i = i + 1; + } + return i; +} +// CHECK: {{.*}}failure_notes.cpp:[[@LINE-11]]:23: error: verification failed: loop [postcondition] [backend=z3] [reason=counterexample] +// CHECK-NEXT: {{^ *}}[[@LINE-12]] | cv::post(cv::result == 0){{$}} +// CHECK-NEXT: {{^}} | ~~~~~~~~~~~^~~~{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-14]]:23: note: counterexample: n = [[N:[1-5]]], i = 0 -> [[N]], result = [[N]] +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-12]]:3: note: enters the loop +// CHECK-NEXT: {{^ *}}[[@LINE-13]] | while (i < n){{$}} +// CHECK-NEXT: {{^}} | ^{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-15]]:3: note: leaves the loop +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-10]]:3: note: returns [[N]] +// CHECK-NEXT: {{^ *}}[[@LINE-11]] | return i;{{$}} +// CHECK-NEXT: {{^}} | ^{{$}} +// CHECK-NEXT: note: the counterexample's state at the loop at [[@LINE-19]]:3 is any state its invariants allow, not necessarily one an execution reaches +// CHECK-NEXT: note: an execution fails this check within 1 iteration of each loop (counterexample: n = 1, i = 0 -> 1, result = 1) + +int long_path(int x) + cv::pre(0 <= x && x <= 100) + cv::post(cv::result < 12) +{ + int c = 0; + if (x > 0) c = c + 1; + if (x > 1) c = c + 1; + if (x > 2) c = c + 1; + if (x > 3) c = c + 1; + if (x > 4) c = c + 1; + if (x > 5) c = c + 1; + if (x > 6) c = c + 1; + if (x > 7) c = c + 1; + if (x > 8) c = c + 1; + if (x > 9) c = c + 1; + if (x > 10) c = c + 1; + if (x > 11) c = c + 1; + return c; +} +// CHECK: {{.*}}failure_notes.cpp:[[@LINE-17]]:23: error: verification failed: long_path [postcondition] [backend=z3] [reason=counterexample] +// CHECK-NEXT: {{^ *}}[[@LINE-18]] | cv::post(cv::result < 12){{$}} +// CHECK-NEXT: {{^}} | ~~~~~~~~~~~^~~~{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-20]]:23: note: counterexample: x = {{[0-9]+}}, c = 0 -> 1 -> 2 -> 3 -> 4 -> 5 -> 6 -> 7 -> 8 -> 9 -> 10 -> 11 -> 12, result = 12 +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-18]]:3: note: takes the true branch +// CHECK-NEXT: {{^ *}}[[@LINE-19]] | if (x > 0) c = c + 1;{{$}} +// CHECK-NEXT: {{^}} | ^{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-20]]:3: note: takes the true branch +// CHECK-NEXT: {{^ *}}[[@LINE-21]] | if (x > 1) c = c + 1;{{$}} +// CHECK-NEXT: {{^}} | ^{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-22]]:3: note: takes the true branch +// CHECK-NEXT: {{^ *}}[[@LINE-23]] | if (x > 2) c = c + 1;{{$}} +// CHECK-NEXT: {{^}} | ^{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-24]]:3: note: takes the true branch +// CHECK-NEXT: {{^ *}}[[@LINE-25]] | if (x > 3) c = c + 1;{{$}} +// CHECK-NEXT: {{^}} | ^{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-26]]:3: note: takes the true branch +// CHECK-NEXT: {{^ *}}[[@LINE-27]] | if (x > 4) c = c + 1;{{$}} +// CHECK-NEXT: {{^}} | ^{{$}} +// CHECK-NEXT: note: (skipping 3 steps of the path; JSON lists every one) +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-26]]:3: note: takes the true branch +// CHECK-NEXT: {{^ *}}[[@LINE-27]] | if (x > 8) c = c + 1;{{$}} +// CHECK-NEXT: {{^}} | ^{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-28]]:3: note: takes the true branch +// CHECK-NEXT: {{^ *}}[[@LINE-29]] | if (x > 9) c = c + 1;{{$}} +// CHECK-NEXT: {{^}} | ^{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-30]]:3: note: takes the true branch +// CHECK-NEXT: {{^ *}}[[@LINE-31]] | if (x > 10) c = c + 1;{{$}} +// CHECK-NEXT: {{^}} | ^{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-32]]:3: note: takes the true branch +// CHECK-NEXT: {{^ *}}[[@LINE-33]] | if (x > 11) c = c + 1;{{$}} +// CHECK-NEXT: {{^}} | ^{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-34]]:3: note: returns 12 +// CHECK-NEXT: {{^ *}}[[@LINE-35]] | return c;{{$}} +// CHECK-NEXT: {{^}} | ^{{$}} + +int two_lines(int x) + cv::pre(0 <= x && x <= 10) + cv::post(cv::result == + x + 1) +{ + return x; +} +// CHECK: {{.*}}failure_notes.cpp:[[@LINE-5]]:23: error: verification failed: two_lines [postcondition] [backend=z3] [reason=counterexample] +// CHECK-NEXT: {{^ *}}[[@LINE-6]] | cv::post(cv::result =={{$}} +// CHECK-NEXT: {{^}} | ^{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-8]]:23: note: counterexample: x = [[X:[0-9]+]], result = [[X]] +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-6]]:3: note: returns [[X]] +// CHECK-NEXT: {{^ *}}[[@LINE-7]] | return x;{{$}} +// CHECK-NEXT: {{^}} | ^{{$}} + + +// JSON keeps every version, and marks those of branches the path does not +// take. +// An archive keeps where each version is defined, so its replay lists the +// same values. +// REPLAY: error: verification failed: steps [postcondition] +// REPLAY-NEXT: note: counterexample: x = {{9|10}}, y = 0 -> 1 -> 4, result = 4 + +// JSON: "function":"steps"{{.*}}{"name":"y","on_path":false,"sort":"i32",{{.*}}"ssa_name":"y_3","value":"0"} + +#define BUMP_IF_LARGE(v) if ((v) > 5) (v) = (v) + 1 + +int in_macro(int x) + cv::pre(0 <= x && x <= 10) + cv::post(cv::result <= 6) +{ + int y = x; + BUMP_IF_LARGE(y); + return y; +} +// CHECK: {{.*}}failure_notes.cpp:[[@LINE-6]]:23: error: verification failed: in_macro [postcondition] [backend=z3] [reason=counterexample] +// CHECK-NEXT: {{^ *}}[[@LINE-7]] | cv::post(cv::result <= 6){{$}} +// CHECK-NEXT: {{^}} | ~~~~~~~~~~~^~~~{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-9]]:23: note: counterexample: x = [[X:[6-9]|10]], y = [[X]] -> [[Y:[0-9]+]], result = [[Y]] +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-7]]:3: note: takes the true branch +// CHECK-NEXT: {{^ *}}[[@LINE-8]] | BUMP_IF_LARGE(y);{{$}} +// CHECK-NEXT: {{^}} | ^{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-9]]:3: note: returns [[Y]] + +int negated(int x) + cv::post(cv::result >= 0 || cv::result < 0) +{ + return -x; +} +// CHECK: {{.*}}failure_notes.cpp:[[@LINE-2]]:3: error: verification failed: negated [overflow] [backend=z3] [reason=counterexample] +// CHECK-NEXT: {{^ *}}[[@LINE-3]] | return -x;{{$}} +// CHECK-NEXT: {{^}} | ^{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-5]]:3: note: counterexample: x = -2147483648 +// CHECK-NOT: note: +// CHECK: error: verification failed: bump + +void bump(int *p) + cv::pre(p != nullptr) + cv::modifies(*p) +{ + *p = *p + 1; +} +// CHECK: {{.*}}failure_notes.cpp:[[@LINE-2]]:6: note: counterexample: p = {{[0-9]+}} +// CHECK-NOT: note: +// CHECK: Summary: + +// BMC unrolls the loop, so its path runs the iterations one by one. +// BMC: error: verification failed: loop [postcondition] [backend=bmc, bound=1] [reason=counterexample] +// BMC: note: counterexample: n = 1, i = 0 -> 1, result = 1 +// BMC-NEXT: note: runs iteration 1 of the loop From dc0f99fcac277ab9db99c706559619d4bc0dab53 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:27 +0530 Subject: [PATCH 033/259] test: Read archive schema v4 and write records of schema v3. --- .../suite/Inputs/mutate_obligation_archive.py | 25 ++++++++++++++++--- 1 file changed, 22 insertions(+), 3 deletions(-) diff --git a/clang/test/Verify/suite/Inputs/mutate_obligation_archive.py b/clang/test/Verify/suite/Inputs/mutate_obligation_archive.py index 64dfac1893..9227cec37b 100644 --- a/clang/test/Verify/suite/Inputs/mutate_obligation_archive.py +++ b/clang/test/Verify/suite/Inputs/mutate_obligation_archive.py @@ -23,6 +23,8 @@ def __init__(self, data): # earlier schema has not. self.measure_spans = [] self.measures = [] + # What schema 4 adds: where each diagnostic variable is defined. + self.guard_spans = [] self.modules = [] def u8(self): @@ -161,6 +163,11 @@ def module(self): self.string() self.diagnostic_sorts.append(self.sort(track=False)) self.source() + if self.version >= 4: + start = self.offset + if self.u8(): + self.expression(track=False) + self.guard_spans.append((start, self.offset)) for _ in range(self.u64()): self.trace_kind_offsets.append(self.offset) self.offset += 1 @@ -368,6 +375,8 @@ def invalidate_quantifier_binder_sort(self, node): "schema-v1", "schema-v1-kinds", "schema-v2", + "schema-v3", + "invalid-guard-flag", "measure-free-variable", "truncated", ], @@ -382,6 +391,12 @@ def invalidate_quantifier_binder_sort(self, node): if args.mode == "invalid-kind": archive.data[archive.expression_kind_offsets[0]] = 255 +elif args.mode == "schema-v3": + for offset in archive.version_offsets: + struct.pack_into(" 3: archive.data[offset] = 1 - # Records before schema 3 have no measures or premises; a premise - # inside a measure goes with it. - spans = sorted(archive.measure_spans) + # Records before schema 3 have no measures or premises, and none before + # schema 4 a variable's guard; a premise inside a measure goes with it. + spans = sorted(archive.measure_spans + archive.guard_spans) outer = [ span for span in spans @@ -400,6 +415,10 @@ def invalidate_quantifier_binder_sort(self, node): ] for start, end in reversed(outer): del archive.data[start:end] +elif args.mode == "invalid-guard-flag": + if not archive.guard_spans: + raise ValueError("archive has no diagnostic variable") + archive.data[archive.guard_spans[0][0]] = 2 elif args.mode == "measure-free-variable": def first_variable(node): if node is None: From eb14c151983dc4cdc90d572d4756e9439e60186b Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:28 +0530 Subject: [PATCH 034/259] test: Replay archive schema v3 and reject an invalid guard flag. --- clang/test/Verify/suite/obligation_archive.test | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/obligation_archive.test b/clang/test/Verify/suite/obligation_archive.test index 61e78e97d0..e22bdbaab1 100644 --- a/clang/test/Verify/suite/obligation_archive.test +++ b/clang/test/Verify/suite/obligation_archive.test @@ -15,7 +15,7 @@ # RUN: %python %S/Inputs/mutate_obligation_archive.py truncated %t.one %t.truncated # RUN: not %cpp-verify --obligation-in=%t.truncated 2>&1 | FileCheck %s --check-prefix=TRUNCATED # RUN: cp %t.one %t.version -# RUN: printf '\004\000\000\000' | dd of=%t.version bs=1 seek=8 conv=notrunc 2>/dev/null +# RUN: printf '\005\000\000\000' | dd of=%t.version bs=1 seek=8 conv=notrunc 2>/dev/null # RUN: not %cpp-verify --obligation-in=%t.version 2>&1 | FileCheck %s --check-prefix=VERSION # RUN: %python %S/Inputs/mutate_obligation_archive.py schema-v1 %t.one %t.schema-v1 # RUN: not %cpp-verify --obligation-in=%t.schema-v1 2>&1 | FileCheck %s --check-prefix=SCHEMA-V1 @@ -23,6 +23,10 @@ # RUN: %cpp-verify --obligation-in=%t.schema-v1-kinds --backend=z3 | FileCheck %s --check-prefix=SCHEMA-V1-KINDS # RUN: %python %S/Inputs/mutate_obligation_archive.py schema-v2 %t.one %t.schema-v2 # RUN: %cpp-verify --obligation-in=%t.schema-v2 --backend=z3 | FileCheck %s --check-prefix=SCHEMA-V2 +# RUN: %python %S/Inputs/mutate_obligation_archive.py schema-v3 %t.one %t.schema-v3 +# RUN: %cpp-verify --obligation-in=%t.schema-v3 --backend=z3 | FileCheck %s --check-prefix=SCHEMA-V3 +# RUN: %python %S/Inputs/mutate_obligation_archive.py invalid-guard-flag %t.one %t.guard-flag +# RUN: not %cpp-verify --obligation-in=%t.guard-flag 2>&1 | FileCheck %s --check-prefix=GUARD-FLAG # A measure is read like a definition, over the function's parameters. # RUN: %cpp-verify --lower-only --obligation-out=%t.measures %S/Inputs/lean_replay.cpp -- # RUN: %python %S/Inputs/mutate_obligation_archive.py measure-free-variable %t.measures %t.measure-variable @@ -99,7 +103,7 @@ # REPLAY: Proved obligations: canonical_obligations (dependencies not checked in replay) [backend=z3] [semantic-hash=sha256:{{[0-9a-f]+}}] # LOWER: vc canonical_obligations -# LOWER: schema cppverify.obligation/3 +# LOWER: schema cppverify.obligation/4 # LOWER: (let # LOWER: Lowered: canonical_obligations [backend=z3] [semantic-hash=sha256:{{[0-9a-f]+}}] # LEAN: Exported: lean obligation: canonical_obligations [backend=lean] @@ -111,6 +115,8 @@ # SCHEMA-V1: error: invalid obligation archive: invalid obligation kind in obligation archive # SCHEMA-V1-KINDS: Proved obligations: canonical_obligations (dependencies not checked in replay) [backend=z3] # SCHEMA-V2: Proved obligations: canonical_obligations (dependencies not checked in replay) [backend=z3] +# SCHEMA-V3: Proved obligations: canonical_obligations (dependencies not checked in replay) [backend=z3] +# GUARD-FLAG: error: invalid obligation archive: invalid diagnostic variable guard in obligation archive # MEASURE: error: invalid obligation archive: logical function definition has a free variable: z # KIND: error: invalid obligation archive: invalid expression kind in obligation archive # FEATURES: error: invalid obligation archive: obligation archive feature declaration does not match contents From ac459b6993b36b828dcdd43d459bee66c86a268d Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:28 +0530 Subject: [PATCH 035/259] test: Expect archive schema v4 in obligation dumps. --- clang/test/Verify/suite/obligation_ir.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/obligation_ir.cpp b/clang/test/Verify/suite/obligation_ir.cpp index 275fc316d6..492a39b6c8 100644 --- a/clang/test/Verify/suite/obligation_ir.cpp +++ b/clang/test/Verify/suite/obligation_ir.cpp @@ -28,7 +28,7 @@ int canonical_obligations(int x) } // OBLIGATION-LABEL: vc canonical_obligations -// OBLIGATION-NEXT: schema cppverify.obligation/3 +// OBLIGATION-NEXT: schema cppverify.obligation/4 // OBLIGATION-NEXT: simplification nodes {{[1-9][0-9]*}} -> {{[1-9][0-9]*}}, rewrites {{[1-9][0-9]*}}, functions-removed 0 // OBLIGATION-NEXT: semantic-hash sha256:f6d09cd4e2ac5c541fa8e0e443f4c2981e5763ce9b4d94d69f9856eaa1e95f2e // OBLIGATION-NEXT: identity [[IDENTITY:fn_[0-9a-f]+]] From 451d61f19f6bf0c1d3c62e748384db146d6f6e3e Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:29 +0530 Subject: [PATCH 036/259] test: Expect proofs as remarks at their functions in a compilation. --- clang/test/Verify/suite/contracts_link_check.test | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/clang/test/Verify/suite/contracts_link_check.test b/clang/test/Verify/suite/contracts_link_check.test index db269ac4ee..05ae98e817 100644 --- a/clang/test/Verify/suite/contracts_link_check.test +++ b/clang/test/Verify/suite/contracts_link_check.test @@ -18,10 +18,10 @@ # RUN: | FileCheck %s --check-prefix=MISSING # # Through the compiler, each object's record beside it. -# RUN: %clang -std=c++17 -fverify-contracts -fverify-contracts-out=%t/a.o.cppverify \ +# RUN: %clang -std=c++17 -fverify-contracts -Rcppverify -fverify-contracts-out=%t/a.o.cppverify \ # RUN: -c %S/Inputs/across/src/a.cpp -o %t/a.o -I%S/Inputs/across/include 2>&1 \ -# RUN: | FileCheck %s --check-prefix=APART -# RUN: %clang -std=c++17 -fverify-contracts -fverify-contracts-out=%t/m.o.cppverify \ +# RUN: | FileCheck %s --check-prefix=REMARK +# RUN: %clang -std=c++17 -fverify-contracts -Rcppverify -fverify-contracts-out=%t/m.o.cppverify \ # RUN: -c %S/Inputs/across/src/mathx.cpp -o %t/m.o -I%S/Inputs/across/include -DBUG=100 # RUN: %cpp-verify --check-contracts %t/a.o.cppverify %t/m.o.cppverify 2>&1 \ # RUN: | FileCheck %s --check-prefix=RIGHT @@ -45,6 +45,10 @@ A proof that rests on a contract of another file says so. APART: Verified: scaled [backend=z3] [assumes=clamp100] APART-NEXT: Verified: twice_scaled [backend=z3] [assumes=clamp100] +Through the compiler each proof is a remark at its function. +REMARK: a.cpp:3:5: remark: Verified: scaled [backend=z3] [assumes=clamp100] [-Rcppverify] +REMARK: a.cpp:9:5: remark: Verified: twice_scaled [backend=z3] [assumes=clamp100] [-Rcppverify] + WRONG: a.cpp:3:5: error: the proof of scaled relies on the contract of clamp100, which its verification in {{.*}}mathx.cpp does not establish WRONG-NEXT: a.cpp:9:5: error: the proof of twice_scaled relies on the contract of clamp100, which its verification in {{.*}}mathx.cpp does not establish WRONG-NEXT: Contracts: 2 proofs rest on contracts of other files, 2 on one not established From d28040b2eff5b54aa1f4afa1bde9da54f51c6792 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:29 +0530 Subject: [PATCH 037/259] docs: Show a failure as a Clang diagnostic in the README. --- README.md | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f2aface8d0..d13891a5e4 100644 --- a/README.md +++ b/README.md @@ -165,9 +165,16 @@ Z3 runs support deterministic isolated solving (`--jobs`) and positive-proof reu (`--proof-cache`). A query past `--timeout` or `--solver-rlimit` is reported as *unresolved* rather than hanging — never as verified. `--int-encoding` only chooses how machine integers reach the solver; every choice is exact, so it can change speed -but never a verdict. A failure names the function and the obligation that failed, -`::@line:column`, e.g. -`verification failed: abs [fn_5f5a3361627369::overflow@5:3]`. +but never a verdict. A failure is a compiler error at the failing source, naming +the function and the kind of check, with its counterexample and path as notes; +without its precondition, `abs` gives: + +```text +abs.cpp:4:3: error: verification failed: abs [overflow] [backend=z3] [reason=counterexample] + 4 | return x < 0 ? -x : x; + | ^ +abs.cpp:4:3: note: counterexample: x = -2147483648 +``` Chained modular calls (e.g. `return inc(inc(x))`) are lowered to temporaries automatically. See [Chapter 17](https://swayaminsync.github.io/cpp-verify/book/part-ii/ch17-backends-modular-calls.html). From 0dc9108999824c556619ca7cfbd63399d8f0e7e0 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:30 +0530 Subject: [PATCH 038/259] docs: Describe how a failure renders as Clang diagnostics, and archive schema v4. --- docs/ARCHITECTURE.md | 51 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 44 insertions(+), 7 deletions(-) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index e4959d9b4b..d35c138a6e 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -1061,7 +1061,7 @@ and obligation kinds. ### Canonical archives and semantic identity `--obligation-out=FILE` writes one or more deterministic -`cppverify.obligation/3` records after source attribution. The binary format has +`cppverify.obligation/4` records after source attribution. The binary format has the `CPVOBL\r\n` magic, an explicit schema version, little-endian fixed-width integers, length-delimited strings/collections, and stable hand-assigned wire tags rather than C++ enum ordinals. The reader bounds strings, collections, @@ -1085,9 +1085,12 @@ functions a measure applies, so a module never names one it does not declare. Before, a spec only a measure applied was removed, and the measure could not be printed. -Schema v2 adds the precise obligation kinds, and schema v3 the measures and -premises; readers still read schema v2 and schema v1, whose records name -only assertions, postconditions, and unwinding checks. Records +Schema v2 adds the precise obligation kinds, schema v3 the measures and +premises, and schema v4, with the diagnostic metadata, where each variable +version is defined (`DiagnosticVariable::Guard`); readers still read schemas +v3, v2, and v1, whose records name only assertions, postconditions, and +unwinding checks. A record before v4 gives no version a guard, so its +counterexamples list every version, as before 0.2. Records limit strings to 64 MiB, collections and expression nodes/edges to 100,000 per record, expression nesting to 4096, canonical integer numerals to 4096 decimal characters, and integer sorts to 4096 bits. @@ -2398,8 +2401,42 @@ obligation's counterexample query to true. Public obligation identities are source anchored: `function-identity::kind@line:column`, with `#N` only for obligations sharing one anchor. This keeps later IDs stable when an unrelated obligation is inserted -or reordered without moving the source anchor. The ordinary diagnostic is -Clang-style text; `--diagnostics-format=json` emits one +or reordered without moving the source anchor; JSON records carry it, and text +names only the kind (`[overflow]`), since the location prefixes the line. + +Every result is described once as Clang diagnostics (`Verifier::partsOf`, +`VerifyDiagnosticPart`): an error at the failing check, with notes; a +warning; or a verdict's status line, an error when unresolved and otherwise +a remark. The error's caret is the obligation's location and its range the +expression it checks when that lies on the caret's line: every `VExpr` +carries the start of its source (`BeginLoc`, Clang's `getBeginLoc`) beside +`Loc` (`getExprLoc`, an operator's position) and `EndLoc`, and lowering keeps +it to `Obligation::BeginLoc` and `VerifyResult::BeginLocation`. A failure's +notes are its counterexample at the check (`counterexampleText`: values by +display name, ordered by the declaration's position with `result` last, each +variable with the values its SSA versions take in version order, `0 -> 1`, a +version that keeps the value before it adding none, and a reference shown as +`&r`, since its value is the address it refers to) and each trace event at +its source location (`traceStepText`, in the static analyzer's words: "takes +the false branch", "returns 151"; a path of more than `TraceStepLimit` steps +keeps its first and last five, as `-ftemplate-backtrace-limit` does), then its +own notes. A note inside a macro is placed at the macro's use: the error +already shows the expansion. Only the versions the path defines count: +passivization records with each version of a source variable the path +condition active where it is defined (`PassiveModelVariable::Guard`, lowered +to `DiagnosticVariable::Guard`, which archives do not record), Z3 evaluates +it in the model without completion (`VerifyModelValue::OnPath`, JSON +`"on_path": false`), and a version whose condition is false is left out: it +equals the version before it there, so listing it showed `y = 0 -> 1 -> 0 -> +1` for a `y` that never returned to 0. A store, a deletion, and a return are +traced after the checks of their own operation, so a check that fails there +does not list the operation as a step taken. A failed result's +`Message` explains only what its model and trace do not, such as a +confirmation by proof; the values are never rendered into it. The standalone +tool prints errors and warnings with `TextDiagnostic`, source line and caret +included, and verdicts as one line each; the compile path reports every part +through the compiler's `DiagnosticsEngine` (see Compile-Time Integration). +`--diagnostics-format=json` emits one `cppverify.diagnostic/1` JSON object per verification result, including source ranges, typed model values, trace events, backend/bound, and a stable reason code. Command-line/frontend errors and output combined with IR dumps are not a @@ -3016,7 +3053,7 @@ semantics. ## Compile-Time Integration -`CppVerifyIntegration` (`clang/lib/Verify/Driver/CppVerifyIntegration.cpp`) hooks **CodeGen**: when `-fverify-contracts` is on and `-fno-verify` is off, verification runs asynchronously while LLVM IR is generated. Failures surface as `diag::err_fe_cppverify_failed`. Zero ghost/spec code in the object file. +`CppVerifyIntegration` (`clang/lib/Verify/Driver/CppVerifyIntegration.cpp`) hooks **CodeGen**: when `-fverify-contracts` is on and `-fno-verify` is off, verification runs asynchronously while LLVM IR is generated. The verifier's thread collects its results as `VerifyDiagnosticPart`s (`VerifyOptions::Parts`) instead of printing them, and `finishCppVerify` reports each through the compiler's `DiagnosticsEngine` on the main thread, which the engine requires: `err_cppverify_result` for failures and unresolved results, `warn_cppverify_result` in `-Wcppverify`, `remark_cppverify_result` in `-Rcppverify` for proofs, and `note_cppverify_result` for their notes. A result without a location of its own, as a proof has none, points at its function's declaration (`VerifyDiagnostic::FunctionLoc`). So `-Werror`, `-w`, colors, `-fdiagnostics-format=sarif`, and clangd see them as Clang's own; `err_fe_cppverify_failed` is reported only when the run fails without a result of its own. Zero ghost/spec code in the object file. ## Tooling Integration From 9dca4de878989937a7c6161fe35c501809620597 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:30 +0530 Subject: [PATCH 039/259] docs: Note archive schema v4. --- docs/DESIGN.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/DESIGN.md b/docs/DESIGN.md index c128a9777d..a0c886149b 100644 --- a/docs/DESIGN.md +++ b/docs/DESIGN.md @@ -2281,10 +2281,11 @@ dead declarations or trivial Boolean structure. It does not rewrite arithmetic, quantifiers, pointer/heap expressions, or assumptions. `--obligation-out=FILE` publishes deterministic, concatenable -`cppverify.obligation/3` binary records with stable wire tags and portable +`cppverify.obligation/4` binary records with stable wire tags and portable source attribution; schema v3 adds each logical function's termination measures and, with source attribution, where each assumption of a goal comes -from, neither hashed, and records of schemas v1 and v2 remain readable. Publication includes an +from, schema v4 where each variable version of a counterexample is defined, +none of them hashed, and records of schemas v1 to v3 remain readable. Publication includes an exact serialize/deserialize/validate/reserialize check. SHA-256 module and per-obligation semantic hashes exclude source paths, display-only names, both positional and source-anchored obligation IDs, and every obligation kind except From 834109b04a972719d34b18b667ecb7d9e4b684dc Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:31 +0530 Subject: [PATCH 040/259] docs: Note failures as Clang diagnostics and archive schema v4. --- website/source/release-notes.rst | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/website/source/release-notes.rst b/website/source/release-notes.rst index bb81c0be47..2d43fb50cb 100644 --- a/website/source/release-notes.rst +++ b/website/source/release-notes.rst @@ -483,6 +483,29 @@ are errors at the statement (:doc:`language/functions-loops`). Running cpp-verify ~~~~~~~~~~~~~~~~~~ +**Failures read like compiler errors.** A failure was one line that named its +obligation by an internal identity and listed every SSA version of every +variable with its type (``verification failed: abs +[fn_5f5a3361627369::overflow@5:3] (counterexample: x [ssa=x_0] [type=i32] = +-2147483648; trace: return.return@5:3 value=-2147483648)``). It is now a Clang +error at the failing source, with the line and a caret under the check, the +kind of check in brackets, the counterexample as a note in source names (each +variable once with the values it takes along the path joined by ``->``, a +hidden local told apart by its line, a reference as ``&r``), and each step of +the path as a note at its line, in the static analyzer's words (``takes the +true branch``, ``calls f(3)``, ``returns -2147483648``); a long path shows its +first and last five steps. The values no longer include those of branches the +path does not take, which the old list gave as if they were values of the +execution, and a check that fails at a store, a ``delete``, or a ``return`` no +longer lists that operation as a step taken (in JSON as well). A ``clang++ -fverify-contracts`` compilation reports each result as a +diagnostic of its own instead of printing the verifier's text and then one +``verification failed`` error: a failure or an unresolved result is an error, +a warning belongs to ``-Wcppverify`` (so ``-Wno-cppverify`` and +``-Werror=cppverify`` work), a proof is a remark shown with ``-Rcppverify``, +and ``-fdiagnostics-format=sarif`` carries them all. In JSON Lines a record's +``message`` is the new error text; its other fields are unchanged +(:doc:`language/tooling`). + **Counterexamples after a loop.** A failure whose counterexample passed through a loop looked like any other, though its state there came from the loop's invariants and no execution need reach it: the first loop most users @@ -758,8 +781,9 @@ refuses a ``lake`` outside elan that reports another Lean Data formats ~~~~~~~~~~~~ -Archives are ``cppverify.obligation/3``, which adds measures and the -sources of assumptions and reads ``/2`` and ``/1``; JSON diagnostics stay +Archives are ``cppverify.obligation/4``, which adds measures, the sources +of assumptions, and where each variable version is defined, and reads ``/3``, +``/2``, and ``/1``; JSON diagnostics stay ``cppverify.diagnostic/1``. A module whose specs' measures apply other specs keeps them, so its module hash changes; per-obligation hashes, and the proof cache keyed by them, do not. JSON records may carry the status From 0624186e39d8bcf6d8cbd3235806bb7055f1975c Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:31 +0530 Subject: [PATCH 041/259] docs: Document failures as Clang diagnostics, in cpp-verify and in a compilation. --- website/source/language/tooling.rst | 120 ++++++++++++++++++++++------ 1 file changed, 95 insertions(+), 25 deletions(-) diff --git a/website/source/language/tooling.rst b/website/source/language/tooling.rst index 9908336b77..e23d9bcdbf 100644 --- a/website/source/language/tooling.rst +++ b/website/source/language/tooling.rst @@ -205,8 +205,31 @@ one line that counts them: .. code-block:: text Verified: add_one [backend=z3] - summary.cpp:14:23: error: verification failed: add_two [fn_...::postcondition@14:23] (counterexample: result [ssa=__result_1] [type=i32] = 5, x [ssa=x_0] [type=i32] = 3; trace: return.return@16:3 value=5) [backend=z3] [reason=counterexample] - Summary: 1 verified, 1 failed in 0.1 s + summary.cpp:14:23: error: verification failed: add_two [postcondition] [backend=z3] [reason=counterexample] + 14 | cv::post(cv::result == twice(x)) + | ~~~~~~~~~~~^~~~~~~~~~~ + summary.cpp:14:23: note: counterexample: x = 3, result = 5 + summary.cpp:16:3: note: returns 5 + 16 | return x + 2; + | ^ + Summary: 1 verified, 1 failed in 0.0 s + +A failure prints as Clang prints an error: the kind of check that fails +(``[postcondition]``), the backend and the reason, and the source with a caret +under the check; then a note with the counterexample's values by their source +names, in the order the source declares them (``result`` last), each with +the values it takes along the path in turn (``i = 0 -> 1``), not those of +branches the path does not take, and a reference as the address it refers to +(``&r = 4``); then a note at each step +of the path it takes: the branches, the calls with their arguments, a loop's +entry and an arbitrary iteration of it, the memory it writes, and the value it +returns. A path of more than ten steps shows its first and last five. A step +inside a macro is shown where the macro is used, and an operation whose own +check fails is no step of the path: a failing check in ``return e;`` ends the +path before the return. A value +the counterexample does not determine is ````. JSON keeps what the +text leaves out (see `Structured diagnostics`_). Errors and warnings show their +source line the same way; verdicts are one line each. The summary counts each kind of verdict the run reported (verified, which includes ``Certified`` and ``Proved (z3+lean)``, failed, unresolved, @@ -829,9 +852,8 @@ kernel checking is required. Structured diagnostics ---------------------- -Failed Z3, cvc5, portfolio, and BMC results identify a source-anchored -obligation such as ``function-identity::overflow@line:column#2``. The kind says -what the obligation checks: +A failure names the kind of the check that fails, as ``[overflow]``. The +kind says what the check is: - contracts: ``assertion``, ``precondition``, ``postcondition``, ``invariant-entry``, ``invariant-preserved``, ``termination``, @@ -851,20 +873,22 @@ what the obligation checks: verifier rejects fail-closed. The check that a function's contract is defined (see :doc:`functions-loops`) -is reported only when it fails, as ``contract of f``. Its obligations are -named ``function-identity::contract::kind@line:column`` with the definedness -kinds above, and JSON records give ``f`` as the function. - -The local suffix only disambiguates obligations of one kind at the same anchor, -so inserting or reordering an unrelated obligation does not renumber later IDs -unless its source anchor moves. JSON records carry the kind as -``obligation.kind``. Diagnostics include inclusive source ranges and source -display names while retaining internal SSA names for unambiguous tooling. - -Counterexample values carry exact sorts such as ``bool``, ``i32``, ``u32``, -``math-i32``, ``pointer``, and ``heap``. Z3 model completion is disabled: -undetermined values print as ```` and become JSON ``null``. Signed and -unsigned bit-vectors are decoded to source-level decimal values. +is reported only when it fails, as ``contract of f``, with the definedness +kinds above; JSON records give ``f`` as the function. + +JSON records also carry each failing check's source-anchored ID, such as +``function-identity::overflow@line:column#2``, as ``obligation.id``, and its +kind as ``obligation.kind``. The local suffix only disambiguates checks of one +kind at the same anchor, so inserting or reordering an unrelated check does +not renumber later IDs unless its source anchor moves. Records include +inclusive source ranges, and each counterexample value has its source name, +its internal SSA name (``ssa_name``), and its exact sort, such as ``bool``, +``i32``, ``u32``, ``math-i32``, ``pointer``, and ``heap``. Z3 model completion +is disabled: undetermined values print as ```` and become JSON +``null``. Signed and unsigned bit-vectors are decoded to source-level decimal +values. A record's ``message`` is the text of its error line; the values and +the path are in ``model`` and ``trace``. Before 0.2 the message also held the +check's ID and every value with its SSA name and sort. Counterexample traces may contain guarded branch, modular-call, loop, heap-write, allocation/provenance, lifetime-end, deletion, and return events. @@ -909,9 +933,21 @@ counts each function once: .. code-block:: text $ cpp-verify --max-failures=0 three_bugs.cpp - three_bugs.cpp:7:3: error: verification failed: three_bugs [fn_...::division-by-zero@7:3] (counterexample: x [ssa=x_0] [type=i32] = 0, y [ssa=y_0] [type=i32] = 0) [backend=z3] [reason=counterexample] - three_bugs.cpp:8:3: error: verification failed: three_bugs [fn_...::overflow@8:3] (counterexample: q [ssa=q_1] [type=i32] = -1, x [ssa=x_0] [type=i32] = -2147483648, y [ssa=y_0] [type=i32] = -9) [backend=z3] [reason=counterexample] - three_bugs.cpp:5:23: error: verification failed: three_bugs [fn_...::postcondition@5:23] (counterexample: result [ssa=__result_1] [type=i32] = 0, q [ssa=q_1] [type=i32] = 0, r [ssa=r_1] [type=i32] = 0, x [ssa=x_0] [type=i32] = 0, y [ssa=y_0] [type=i32] = 11; trace: return.return@9:3 value=0) [backend=z3] [reason=counterexample] + three_bugs.cpp:7:3: error: verification failed: three_bugs [division-by-zero] [backend=z3] [reason=counterexample] + 7 | int q = 10 / y; + | ^ + three_bugs.cpp:7:3: note: counterexample: x = 0, y = 0 + three_bugs.cpp:8:3: error: verification failed: three_bugs [overflow] [backend=z3] [reason=counterexample] + 8 | int r = x + q; + | ^ + three_bugs.cpp:8:3: note: counterexample: x = -2147483648, y = -9, q = -1 + three_bugs.cpp:5:23: error: verification failed: three_bugs [postcondition] [backend=z3] [reason=counterexample] + 5 | cv::post(cv::result > 0) + | ~~~~~~~~~~~^~~ + three_bugs.cpp:5:23: note: counterexample: x = 0, y = 11, q = 0, r = 0, result = 0 + three_bugs.cpp:9:3: note: returns 0 + 9 | return r; + | ^ Summary: 1 failed in 0.0 s Without the option only the first line is printed. The overflow's @@ -1064,7 +1100,7 @@ module is ``BoundedSafe`` when every goal but some unwinding goal certifies (:doc:`../book/part-ii/ch17-backends-modular-calls`). ``--lean-fallback`` applies to source verification only. -``--obligation-out`` writes ``cppverify.obligation/3`` records only after exact +``--obligation-out`` writes ``cppverify.obligation/4`` records only after exact serialize/deserialize/validate/reserialize checks. Stable wire tags make the format independent of C++ enum ordinals. The reader rejects malformed magic, unsupported versions, truncation, invalid tags, inconsistent feature @@ -1072,8 +1108,11 @@ declarations, duplicate identities, and oversized/deep expressions. Schema v2 adds the precise obligation kinds; schema v3 each spec function's termination measures, read like its definition, and, with source metadata, where each assumption of a goal comes from, which names a hypothesis of a -readable Lean goal. Records of schema v2, and of schema v1, which name only -assertions, postconditions, and unwinding checks, are still read. +readable Lean goal; schema v4, with source metadata, where each variable +version of a counterexample is defined, so a replayed counterexample lists the +values its path takes. Records of schemas v3 and v2, and of schema v1, which +name only assertions, postconditions, and unwinding checks, are still read; a +counterexample replayed from one before v4 lists the values of every version. Records cap integer widths at 4096 bits, expression depth at 4096, and collections plus expression nodes/edges at 100,000 per record. It also rejects embedded NULs, non-canonical numerals, inactive payload fields, ill-scoped @@ -1156,6 +1195,37 @@ contract syntax, **and** contract semantics (the ``cppverify::old``/``cppverify: bool-convertibility rules), but does **not** check your logic. Ideal for editors, CI pre-flight, and LLM/agent loops. +Results in a compilation +~~~~~~~~~~~~~~~~~~~~~~~~ + +``clang++ -fverify-contracts`` reports what it verifies as its own +diagnostics, in the format ``cpp-verify`` prints: a failure is an error with +its notes, an unresolved result is an error, a warning is a warning in +``-Wcppverify`` (``-Wno-cppverify`` hides it and ``-Werror=cppverify`` makes it +an error), and a proof is a remark at its function, shown with +``-Rcppverify``. Colors, +``-fdiagnostics-format=sarif``, and editors that read the compiler's +diagnostics show them as they show Clang's: + +.. code-block:: text + + $ clang++ -std=c++17 -fverify-contracts -Rcppverify -c summary.cpp -o summary.o + summary.cpp:5:5: remark: Verified: add_one [backend=z3] [-Rcppverify] + 5 | int add_one(int x) + | ^ + summary.cpp:14:23: error: verification failed: add_two [postcondition] [backend=z3] [reason=counterexample] + 14 | cv::post(cv::result == twice(x)) + | ~~~~~~~~~~~^~~~~~~~~~~ + summary.cpp:14:23: note: counterexample: x = 3, result = 5 + summary.cpp:16:3: note: returns 5 + 16 | return x + 2; + | ^ + 1 error generated. + +Before 0.2 the compiler printed the verifier's lines as text, and then the +one error ``cppverify: verification failed``: ``-fdiagnostics-format=sarif`` +gave a document without results, and ``-w`` and ``-Werror`` changed nothing. + Quick lookup ~~~~~~~~~~~~ From 6009a53e9a1c19fc79c1abc35415aa953cda5d41 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:31 +0530 Subject: [PATCH 042/259] docs: Explain how to read a failure in chapter 16. --- .../part-ii/ch16-when-verification-fails.rst | 38 +++++++++++++++---- 1 file changed, 30 insertions(+), 8 deletions(-) diff --git a/website/source/book/part-ii/ch16-when-verification-fails.rst b/website/source/book/part-ii/ch16-when-verification-fails.rst index 643302f323..67c0d310f3 100644 --- a/website/source/book/part-ii/ch16-when-verification-fails.rst +++ b/website/source/book/part-ii/ch16-when-verification-fails.rst @@ -7,12 +7,18 @@ that as actionable feedback on the code, the contracts, or both. Understanding the report ------------------------ -Diagnostics name the source-anchored obligation that failed and often include a -**counterexample**: typed source-name values that violate the claim, followed by -guarded branch, call, loop, heap/provenance, lifetime, and return events. Use -those values and events to see which assumption or branch is wrong. Values that -Z3 does not determine remain ````; CppVerify does not complete the -model by inventing them. +A failure is a compiler error at the check that fails, with its kind +(``[postcondition]``, ``[overflow]``, ...) and the source line, the failing +expression underlined. Its notes give the **counterexample**: first the values +by their source names, each variable with the values it takes along the path +(``c = 0 -> 1``), then each step of that path at its line, as Clang's static +analyzer reports a path: the branches it takes, the calls with their +arguments, the loops it enters and leaves, the memory it writes, the objects +it creates and ends, and the value it returns. Use those values and steps to +see which assumption or branch is wrong. Values that Z3 does not determine +remain ````; CppVerify does not complete the model by inventing them. +``clang++ -fverify-contracts`` reports the same errors and notes as its own +diagnostics. For editor, CI, and agent integration, run: @@ -52,7 +58,17 @@ loop with too weak an invariant fails a correct function: .. code-block:: text - count_up.cpp:5:23: error: verification failed: count_up [fn_...::postcondition@5:23] (counterexample: result [ssa=__result_1] [type=i32] = 1, c [ssa=c_1] [type=i32] = 0, c [ssa=c_2] [type=i32] = 1, c [ssa=c_3] [type=i32] = 1, n [ssa=n_0] [type=i32] = 0; trace: loop.entry@8:3 -> loop.exit@8:3 -> return.return@13:3 value=1) [backend=z3] [reason=counterexample] + count_up.cpp:5:23: error: verification failed: count_up [postcondition] [backend=z3] [reason=counterexample] + 5 | cv::post(cv::result == n) + | ~~~~~~~~~~~^~~~ + count_up.cpp:5:23: note: counterexample: n = 0, c = 0 -> 1, result = 1 + count_up.cpp:8:3: note: enters the loop + 8 | while (c < n) + | ^ + count_up.cpp:8:3: note: leaves the loop + count_up.cpp:13:3: note: returns 1 + 13 | return c; + | ^ note: the counterexample's state at the loop at 8:3 is any state its invariants allow, not necessarily one an execution reaches note: no execution fails this check: every loop ends within 5 iterations, and unrolling proves it there; the loops' invariants are too weak for an unbounded proof @@ -383,7 +399,13 @@ be its cause: .. code-block:: text - vacuity.cpp:2:28: error: verification failed: contradictory [...::postcondition@2:28] (...) [backend=z3] [reason=counterexample] + vacuity.cpp:2:28: error: verification failed: contradictory [postcondition] [backend=z3] [reason=counterexample] + 2 | cv::post(cv::result == x && cv::result == x + 1) // no result satisfies this + | ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~ + vacuity.cpp:2:28: note: counterexample: x = 2147483647, result = 2147483647 + vacuity.cpp:4:3: note: returns 2147483647 + 4 | return x; + | ^ Unresolved: relies_on_it [backend=z3] [reason=callee.contract] (relies on the contract of contradictory, which is not established) ``relies_on_it`` proves its postcondition only because the contract of From 03f879a761a80fff36e1bec02541d91112fd1782 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:32 +0530 Subject: [PATCH 043/259] docs: Show shadowed loop counters as a counterexample names them. --- website/source/book/part-ii/ch12-loops-in-practice.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/source/book/part-ii/ch12-loops-in-practice.rst b/website/source/book/part-ii/ch12-loops-in-practice.rst index 4a8cb9583f..0034b20421 100644 --- a/website/source/book/part-ii/ch12-loops-in-practice.rst +++ b/website/source/book/part-ii/ch12-loops-in-practice.rst @@ -282,8 +282,8 @@ Two loops may each declare their counter, ``for (int i = 0; ...)``, and a block may declare a name an outer one already has: each declaration is a variable of its own, so the second ``i`` starts uninitialized and neither loop's invariant is about the other's counter. A counterexample shows the -name as written, with the verifier's own name for the second one, ``i#2``, in -``[ssa=...]``. +name as written, with the line of its declaration when both appear in it: +``i (line 8) = 0 -> 1, i (line 14) = 0 -> 1``. Lexicographic measures ---------------------- From cf6bb08d1758ab3cb713fda3aada947077c20342 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:32 +0530 Subject: [PATCH 044/259] docs: Show failures as Clang diagnostics in the functions and loops reference. --- website/source/language/functions-loops.rst | 156 +++++++++++++++++--- 1 file changed, 133 insertions(+), 23 deletions(-) diff --git a/website/source/language/functions-loops.rst b/website/source/language/functions-loops.rst index f82e325f61..fc295d3207 100644 --- a/website/source/language/functions-loops.rst +++ b/website/source/language/functions-loops.rst @@ -26,9 +26,12 @@ A local may take the name of a parameter or of another local, in an inner block or a later one (two ``for (int i = ...)`` loops, say): each declaration is a variable of its own, uninitialized until it is assigned whatever an earlier one with its name held. A counterexample shows its name as written, -and in ``[ssa=...]`` the verifier's name for it, ``i#2`` for the second ``i``. -Before 0.2 such a declaration was an error, ``local variable shadowing is -unsupported``. +with the line of its declaration when another variable of the +counterexample has that name (``i (line 8) = 0 -> 1, i (line 14) = 0 -> 1`` +for two loops that each declare ``i``); JSON records give the verifier's name +for each version as ``ssa_name``, ``i#2_1`` for the first of the second +``i``. Before 0.2 such a declaration was an error, ``local variable shadowing +is unsupported``. A default argument is evaluated at the call, with the checks of its operations there. A ``consteval`` call, like any constant Clang evaluates, is @@ -172,7 +175,20 @@ otherwise, as within one file. $ cpp-verify src/a.cpp src/mathx.cpp -- -Iinclude Unresolved: scaled [backend=z3] [reason=callee.contract] (relies on the contract of clamp100, which its verification in src/mathx.cpp does not establish) - include/mathx.h:2:42: error: verification failed: clamp100 [fn_...::postcondition@2:42] (counterexample: result [ssa=__result_1] [type=i32] = 101, x [ssa=x_0] [type=i32] = 101; ...) [backend=z3] [reason=counterexample] + In file included from src/mathx.cpp:1: + include/mathx.h:2:28: error: verification failed: clamp100 [postcondition] [backend=z3] [reason=counterexample] + 2 | cv::post(cv::result >= 0 && cv::result <= 100); + | ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~ + include/mathx.h:2:28: note: counterexample: x = 101, result = 101 + src/mathx.cpp:5:3: note: takes the false branch + 5 | if (x < 0) + | ^ + src/mathx.cpp:7:3: note: takes the true branch + 7 | if (x > 100) + | ^ + src/mathx.cpp:8:5: note: returns 101 + 8 | return 101; + | ^ Summary: 1 failed, 1 unresolved (callee.contract 1) in 0.0 s With ``return 100;`` both verify, and the warning that ``clamp100`` has no @@ -326,16 +342,22 @@ that may not be as ``contract of f``, at the operation: .. code-block:: text - defined.cpp:2:17: error: verification failed: contract of average - [...::contract::division-by-zero@2:17] (counterexample: count [type=i32] = 0) + defined.cpp:2:17: error: verification failed: contract of average [division-by-zero] [backend=z3] [reason=counterexample] + 2 | cv::pre(total / count >= 0 && count > 0) + | ^ + defined.cpp:2:17: note: counterexample: count = 0 Verified: average [backend=z3] Verified: average_checked [backend=z3] - defined.cpp:16:30: error: verification failed: contract of pick - [...::contract::bounds@16:30] (counterexample: i [type=i32] = -1, ...) + defined.cpp:16:30: error: verification failed: contract of pick [bounds] [backend=z3] [reason=counterexample] + 16 | cv::pre(cv::valid(p, 8) && p[i] > 0 && 0 <= i && i < 8) + | ^ + defined.cpp:16:30: note: counterexample: p = 1, i = -1 Verified: pick [backend=z3] defined.cpp:22:28: Trusted: read_sensor (contract assumed, not verified) - defined.cpp:23:17: error: verification failed: contract of read_sensor - [...::contract::division-by-zero@23:17] (counterexample: result [type=i32] = 0) + defined.cpp:23:17: error: verification failed: contract of read_sensor [division-by-zero] [backend=z3] [reason=counterexample] + 23 | cv::post(1000 / cv::result > 0); + | ^ + defined.cpp:23:17: note: counterexample: result = 0 Unresolved: scaled [backend=z3] [reason=callee.contract] (relies on the contract of read_sensor (its clauses are not shown to be defined), which is not established) @@ -439,12 +461,24 @@ result. Each call runs where C++ evaluates it: Verified: sq [backend=z3] Verified: sum_sq [backend=z3] Verified: guarded [backend=z3] - calls.cpp:38:7: error: verification failed: unguarded [...::precondition@38:7] - (counterexample: x [type=i32] = -1001; trace: call.sq@38:7 arg0=-1001) - calls.cpp:48:10: error: verification failed: count_up [...::precondition@48:10] - (counterexample: ..., i [type=i32] = 1000, n [type=i32] = 1000; - trace: loop.entry@48:3 -> loop.inductive iteration@48:3 condition=true - -> call.inc@48:10 arg0=1000) + calls.cpp:34:7: error: verification failed: unguarded [precondition] [backend=z3] [reason=counterexample] + 34 | if (sq(x) > 4 && x <= 1000) + | ^ + calls.cpp:34:7: note: counterexample: x = -1001 + calls.cpp:34:7: note: calls sq(-1001) + calls.cpp:44:10: error: verification failed: count_up [precondition] [backend=z3] [reason=counterexample] + 44 | while (inc(i) <= n) + | ^ + calls.cpp:44:10: note: counterexample: n = 1000, i = 0 -> 1000 + calls.cpp:44:3: note: enters the loop + 44 | while (inc(i) <= n) + | ^ + calls.cpp:44:3: note: starts an arbitrary iteration of the loop, where its condition is true + calls.cpp:44:10: note: calls inc(1000) + 44 | while (inc(i) <= n) + | ^ + note: the counterexample's state at the loop at 44:3 is any state its invariants allow, not necessarily one an execution reaches + note: no execution fails this check within 10 iterations of each loop ``guarded`` calls ``sq`` only where ``-1000 <= x && x <= 1000`` holds, so ``sq``'s precondition holds at every call it makes. ``unguarded`` calls @@ -597,8 +631,16 @@ named with its arguments. A template value parameter is its argument, and .. code-block:: text Verified: twice [backend=z3] - templates.cpp:4:23: error: verification failed: twice [...::postcondition@4:23] (counterexample: ...) [backend=z3] [reason=counterexample] + templates.cpp:4:23: error: verification failed: twice [postcondition] [backend=z3] [reason=counterexample] + 4 | cv::post(cv::result == 2 * x) + | ~~~~~~~~~~~^~~~~~~~ + templates.cpp:4:23: note: counterexample: x = 16384, result = -32768 + templates.cpp:6:3: note: returns -32768 + 6 | return x + x; + | ^ templates.cpp:20:13: note: in instantiation of function template specialization 'twice' requested here + 20 | short r = twice(x); + | ^ Verified: twice_int [backend=z3] Unresolved: twice_short [backend=z3] [reason=callee.contract] (relies on the contract of twice, which is not established) @@ -747,7 +789,17 @@ execution that fails the same check, with callees still by their contracts: .. code-block:: text - count_up.cpp:5:23: error: verification failed: count_up [fn_...::postcondition@5:23] (counterexample: result [ssa=__result_1] [type=i32] = 1, c [ssa=c_1] [type=i32] = 0, c [ssa=c_2] [type=i32] = 1, c [ssa=c_3] [type=i32] = 1, n [ssa=n_0] [type=i32] = 0; trace: loop.entry@8:3 -> loop.exit@8:3 -> return.return@13:3 value=1) [backend=z3] [reason=counterexample] + count_up.cpp:5:23: error: verification failed: count_up [postcondition] [backend=z3] [reason=counterexample] + 5 | cv::post(cv::result == n) + | ~~~~~~~~~~~^~~~ + count_up.cpp:5:23: note: counterexample: n = 0, c = 0 -> 1, result = 1 + count_up.cpp:8:3: note: enters the loop + 8 | while (c < n) + | ^ + count_up.cpp:8:3: note: leaves the loop + count_up.cpp:13:3: note: returns 1 + 13 | return c; + | ^ note: the counterexample's state at the loop at 8:3 is any state its invariants allow, not necessarily one an execution reaches note: no execution fails this check: every loop ends within 5 iterations, and unrolling proves it there; the loops' invariants are too weak for an unbounded proof @@ -785,7 +837,14 @@ counterexample, see :doc:`tooling`): .. code-block:: text - divide.cpp:13:7: error: verification failed: divide [fn_...::overflow@13:7] (counterexample: a [ssa=a_0] [type=i32] = -2147483648, c [ssa=c_1] [type=i32] = 0, c [ssa=c_2] [type=i32] = 2, n [ssa=n_0] [type=i32] = 3, q [ssa=q_1] [type=i32] = 0; trace: loop.entry@9:3 -> loop.inductive iteration@9:3 condition=true) [backend=z3] [reason=counterexample] + divide.cpp:13:7: error: verification failed: divide [overflow] [backend=z3] [reason=counterexample] + 13 | q = a / (1 - c); + | ^ + divide.cpp:13:7: note: counterexample: a = -2147483648, n = 3, c = 0 -> 2, q = 0 + divide.cpp:9:3: note: enters the loop + 9 | while (c < n) + | ^ + divide.cpp:9:3: note: starts an arbitrary iteration of the loop, where its condition is true note: the counterexample's state at the loop at 9:3 is any state its invariants allow, not necessarily one an execution reaches note: no execution fails this check without failing an earlier one first (the division-by-zero check at 13:7 fails): those that pass the checks before it end every loop within 2 iterations, and unrolling proves it there @@ -1014,7 +1073,25 @@ other object keeps its value: .. code-block:: text Verified: other_array [backend=z3] - frames.cpp:18:23: error: verification failed: overwritten [...::postcondition@18:23] (counterexample: ...) [backend=z3] [reason=counterexample] + frames.cpp:18:23: error: verification failed: overwritten [postcondition] [backend=z3] [reason=counterexample] + 18 | cv::post(cv::result == 7) + | ~~~~~~~~~~~^~~~ + frames.cpp:18:23: note: counterexample: i = 0 -> 4, result = -2147483648 + frames.cpp:20:3: note: creates a local object at address 4 + 20 | int a[4]; + | ^ + frames.cpp:21:8: note: stores 7 at address 16 + 21 | a[3] = 7; + | ^ + frames.cpp:22:3: note: enters the loop + 22 | for (int i = 0; i < 4; i = i + 1) + | ^ + frames.cpp:22:3: note: leaves the loop + frames.cpp:28:3: note: returns -2147483648 + 28 | return a[3]; + | ^ + note: the counterexample's state at the loop at 22:3 is any state its invariants allow, not necessarily one an execution reaches + note: an execution fails this check within 4 iterations of each loop (counterexample: i = 0 -> 1 -> 2 -> 3 -> 4, result = 0) ``overwritten`` fails because the loop writes ``a[3]``, which no invariant describes. Before 0.2 a loop that wrote local or dynamic storage forgot the @@ -1065,7 +1142,19 @@ contract can say directly: .. code-block:: text Verified: filled [backend=z3] - fill.cpp:26:3: error: verification failed: partially_filled [...::initialization@26:3] (counterexample: ...) [backend=z3] [reason=counterexample] + fill.cpp:25:3: error: verification failed: partially_filled [initialization] [backend=z3] [reason=counterexample] + 25 | return a[3]; + | ^ + fill.cpp:25:3: note: counterexample: i = 0 -> 3 + fill.cpp:17:3: note: creates a local object at address 9132 + 17 | int a[4]; + | ^ + fill.cpp:18:3: note: enters the loop + 18 | for (int i = 0; i < 3; i = i + 1) + | ^ + fill.cpp:18:3: note: leaves the loop + note: the counterexample's state at the loop at 18:3 is any state its invariants allow, not necessarily one an execution reaches + note: an execution fails this check within 3 iterations of each loop (counterexample: i = 0 -> 1 -> 2 -> 3) No lifetime begins or ends inside a loop, so what was initialized before it stays initialized in every iteration and after it; an element the loop may @@ -1135,7 +1224,13 @@ The path ends there, so after ``assert(c)`` the condition holds. With .. code-block:: text Verified: scaled [backend=z3] - aborts.cpp:16:5: error: verification failed: aborts [...::unreachable@16:5] (counterexample: x [ssa=x_0] [type=i32] = -1; ...) [backend=z3] [reason=counterexample] + aborts.cpp:16:5: error: verification failed: aborts [unreachable] [backend=z3] [reason=counterexample] + 16 | abort(); + | ^ + aborts.cpp:16:5: note: counterexample: x = -1 + aborts.cpp:15:3: note: takes the true branch + 15 | if (x < 0) + | ^ An uncontracted ``constexpr`` helper's ``assert(c)`` is a requirement of each call that reaches it, checked at the call as the helper's undefined @@ -1217,7 +1312,22 @@ switch over its enumerators may match none: .. code-block:: text - channel.cpp:4:12: error: verification failed: channel [...::postcondition@4:12] (counterexample: result [ssa=__result_1] [type=i32] = -1, c [ssa=c_0] [type=u32] = 3; ...) [backend=z3] [reason=counterexample] + channel.cpp:4:23: error: verification failed: channel [postcondition] [backend=z3] [reason=counterexample] + 4 | cv::post(cv::result >= 0) + | ~~~~~~~~~~~^~~~ + channel.cpp:4:23: note: counterexample: c = 3, result = -1 + channel.cpp:7:3: note: takes the false branch + 7 | case Red: + | ^ + channel.cpp:9:3: note: takes the false branch + 9 | case Green: + | ^ + channel.cpp:11:3: note: takes the false branch + 11 | case Blue: + | ^ + channel.cpp:14:3: note: returns -1 + 14 | return -1; + | ^ ``Color`` holds 0 to 3, the values of the smallest bit-field that fits its enumerators, and ``channel(Color(3))`` is defined C++ that returns -1. From 2f5a4d95cee4b9142c0ab2cbacef3524218e3825 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:33 +0530 Subject: [PATCH 045/259] docs: Show failures as Clang diagnostics, and archive schema v4, in chapter 17. --- .../book/part-ii/ch17-backends-modular-calls.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/website/source/book/part-ii/ch17-backends-modular-calls.rst b/website/source/book/part-ii/ch17-backends-modular-calls.rst index 9d4ba95f2c..b546a9d096 100644 --- a/website/source/book/part-ii/ch17-backends-modular-calls.rst +++ b/website/source/book/part-ii/ch17-backends-modular-calls.rst @@ -345,7 +345,13 @@ checks a proof, with the kernel and Lean's foundations alone, and says so: .. code-block:: text - error: verification failed: add_one [fn_5f5a376164645f6f6e6569::postcondition@3:37] (counterexample: result [ssa=__result_1] [type=i32] = 6, x [ssa=x_0] [type=i32] = 4; trace: return.return@5:3 value=6) [backend=z3] [reason=counterexample] (confirmed in Lean) + example.cpp:3:37: error: verification failed: add_one [postcondition] [backend=z3] [reason=counterexample] (confirmed in Lean) + 3 | cppverify::post(cppverify::result == x + 1) + | ~~~~~~~~~~~~~~~~~~^~~~~~~~ + example.cpp:3:37: note: counterexample: x = 4, result = 6 + example.cpp:5:3: note: returns 6 + 5 | return x + 2; + | ^ The refutation applies the goal to the model's values and decides what is left false, the definition instances the goal states with it, since they hold @@ -1022,7 +1028,7 @@ The canonical backend boundary can be persisted and replayed: cpp-verify --obligation-in=goals.cpv --backend=lean --lean-out=goals.lean cpp-verify --obligation-in=goals.cpv --lean-project=proof --lean-certify -Each ``cppverify.obligation/3`` record uses stable wire tags, defensive bounds, +Each ``cppverify.obligation/4`` record uses stable wire tags, defensive bounds, portable source points, and path-independent SHA-256 semantic hashes. Replay revalidates every sort, expression, logical declaration, call signature, feature declaration, and identity before backend dispatch. Multiple records may From fac1772b8cbfe400425b65892b1d9d97924f691f Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:33 +0530 Subject: [PATCH 046/259] test: Expect failures as Clang diagnostics in assertions.cpp. --- clang/test/Verify/suite/assertions.cpp | 43 +++++++++++++++----------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/clang/test/Verify/suite/assertions.cpp b/clang/test/Verify/suite/assertions.cpp index 73278119ae..31c15d206c 100644 --- a/clang/test/Verify/suite/assertions.cpp +++ b/clang/test/Verify/suite/assertions.cpp @@ -39,7 +39,8 @@ int checked_wrong(int x) assert(x > 0 && "x must be positive"); return x; } -// CHECK-DAG: error: verification failed: checked_wrong [{{.*}}::unreachable@[[@LINE-3]]:3] (counterexample: x [ssa=x_0] [type=i32] = {{-?[0-9]+}}{{.*}}[reason=counterexample] +// CHECK-DAG: :[[@LINE-3]]:3: error: verification failed: checked_wrong [unreachable] {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}x = {{-?[0-9]+}}{{( ->|,|$)}} // NDEBUG-DAG: Verified: checked_wrong [backend=z3] // MSVC's assert expands to a || whose right operand calls _wassert, which @@ -52,7 +53,7 @@ int msvc_assert(int x) (void)((!!(x > 0)) || (_wassert(L"x > 0", L"assertions.cpp", 1), 0)); return x; } -// CHECK-DAG: error: verification failed: msvc_assert [{{.*}}::unreachable@[[@LINE-3]]:{{.*}}[reason=counterexample] +// CHECK-DAG: :[[@LINE-3]]:{{[0-9]+}}: error: verification failed: msvc_assert [unreachable]{{.*}}[reason=counterexample] // After assert(c), c holds. int positive_after(int x) @@ -62,8 +63,8 @@ int positive_after(int x) assert(x > 0); return x; } -// CHECK-DAG: error: verification failed: positive_after [{{.*}}::unreachable@[[@LINE-3]]:3]{{.*}}[reason=counterexample] -// NDEBUG-DAG: error: verification failed: positive_after [{{.*}}::postcondition@{{.*}}[reason=counterexample] +// CHECK-DAG: :[[@LINE-3]]:3: error: verification failed: positive_after [unreachable]{{.*}}[reason=counterexample] +// NDEBUG-DAG: error: verification failed: positive_after [postcondition]{{.*}}[reason=counterexample] int positive_after_check(int x) cv::pre(x > 0) @@ -81,7 +82,8 @@ int aborts(int x) abort(); return x; } -// CHECK-DAG: error: verification failed: aborts [{{.*}}::unreachable@[[@LINE-3]]:5] (counterexample: x [ssa=x_0] [type=i32] = {{-[0-9]+}}{{.*}}[reason=counterexample] +// CHECK-DAG: :[[@LINE-3]]:5: error: verification failed: aborts [unreachable] {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}x = {{-[0-9]+}}{{( ->|,|$)}} int aborts_guarded(int x) cv::pre(x >= 0) @@ -103,7 +105,8 @@ int exits(int code) std::terminate(); return code; } -// CHECK-DAG: error: verification failed: exits [{{.*}}::unreachable@[[@LINE-3]]:5] (counterexample: code [ssa=code_0] [type=i32] = {{[0-9]+}}{{.*}}[reason=counterexample] +// CHECK-DAG: :[[@LINE-3]]:5: error: verification failed: exits [unreachable] {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}code = {{[0-9]+}}{{( ->|,|$)}} int classify(int x) cv::pre(0 <= x && x < 3) @@ -131,7 +134,8 @@ int classify_wrong(int x) return 3; __builtin_trap(); } -// CHECK-DAG: error: verification failed: classify_wrong [{{.*}}::unreachable@[[@LINE-2]]:3] (counterexample: x [ssa=x_0] [type=i32] = 3{{.*}}[reason=counterexample] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: classify_wrong [unreachable] {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}x = 3{{( ->|,|$)}} // An assumption is proved where it stands, then holds. int assumed(int x) @@ -150,7 +154,8 @@ int assumed_wrong(int x) [[assume(x > 0)]]; return x; } -// CHECK-DAG: error: verification failed: assumed_wrong [{{.*}}::assertion@[[@LINE-3]]:{{.*}}x [ssa=x_0] [type=i32] = {{-?[0-9]+}}{{.*}}[reason=counterexample] +// CHECK-DAG: :[[@LINE-3]]:{{[0-9]+}}: error: verification failed: assumed_wrong [assertion] {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}x = {{-?[0-9]+}}{{( ->|,|$)}} // A discarded value is computed, with its checks; the operands of a // discarded ||, &&, or ?: run on their paths. @@ -161,7 +166,7 @@ int discarded(int x) x + 1; return 0; } -// CHECK-DAG: error: verification failed: discarded [{{.*}}::overflow@[[@LINE-3]]:{{.*}}[reason=counterexample] +// CHECK-DAG: :[[@LINE-3]]:{{[0-9]+}}: error: verification failed: discarded [overflow]{{.*}}[reason=counterexample] int or_else(int x) cv::post(cv::result > 0) @@ -169,7 +174,7 @@ int or_else(int x) x > 0 || (abort(), 0); return x; } -// CHECK-DAG: error: verification failed: or_else [{{.*}}::unreachable@[[@LINE-3]]:{{.*}}[reason=counterexample] +// CHECK-DAG: :[[@LINE-3]]:{{[0-9]+}}: error: verification failed: or_else [unreachable]{{.*}}[reason=counterexample] int or_else_guarded(int x) cv::pre(x > 0) @@ -205,7 +210,7 @@ int use_half_wrong(int x) { return half(x); } -// CHECK-DAG: error: verification failed: use_half_wrong [{{.*}}::unreachable@[[@LINE-2]]:{{.*}}[reason=counterexample] +// CHECK-DAG: :[[@LINE-2]]:{{[0-9]+}}: error: verification failed: use_half_wrong [unreachable]{{.*}}[reason=counterexample] int use_quarter_wrong(int x) cv::pre(-1000 < x && x < 1000 && x % 4 == 2) @@ -213,7 +218,7 @@ int use_quarter_wrong(int x) { return quarter(x); } -// CHECK-DAG: error: verification failed: use_quarter_wrong [{{.*}}::unreachable@[[@LINE-2]]:{{.*}}[reason=counterexample] +// CHECK-DAG: :[[@LINE-2]]:{{[0-9]+}}: error: verification failed: use_quarter_wrong [unreachable]{{.*}}[reason=counterexample] // NDEBUG-DAG: Verified: use_quarter_wrong [backend=z3] // The requirement holds on the helper's path to the call that does not @@ -244,7 +249,8 @@ int use_div_wrong(int a, int b) { return checked_div(a, b); } -// CHECK-DAG: error: verification failed: use_div_wrong [{{.*}}::unreachable@[[@LINE-2]]:{{.*}}b [ssa=b_0] [type=i32] = 0{{.*}}[reason=counterexample] +// CHECK-DAG: :[[@LINE-2]]:{{[0-9]+}}: error: verification failed: use_div_wrong [unreachable] {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}b = 0{{( ->|,|$)}} int use_positive(int x) cv::pre(x > 0) @@ -277,7 +283,7 @@ uint64_t alignTo_zero(uint64_t Value) { return alignTo(Value, 0); } -// CHECK-DAG: error: verification failed: alignTo_zero [{{.*}}::precondition@[[@LINE-2]]:{{.*}}[reason=counterexample] +// CHECK-DAG: :[[@LINE-2]]:{{[0-9]+}}: error: verification failed: alignTo_zero [precondition]{{.*}}[reason=counterexample] inline constexpr uint64_t maxUIntN(uint64_t N) cv::pre(N <= 64) @@ -319,12 +325,13 @@ int64_t SignExtend64_wide(uint64_t X, unsigned B) return 0; return int64_t(X << (64 - B)) >> (64 - B); } -// CHECK-DAG: error: verification failed: SignExtend64_wide [{{.*}}::unreachable@[[@LINE-5]]:3] (counterexample: {{.*}}B [ssa=B_0] [type=u32] = {{[0-9]+}}{{.*}}[reason=counterexample] -// NDEBUG-DAG: error: verification failed: SignExtend64_wide [{{.*}}::shift@{{.*}}[reason=counterexample] +// CHECK-DAG: :[[@LINE-5]]:3: error: verification failed: SignExtend64_wide [unreachable] {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}B = {{[0-9]+}}{{( ->|,|$)}} +// NDEBUG-DAG: error: verification failed: SignExtend64_wide [shift]{{.*}}[reason=counterexample] // BMC: Verified: checked [backend=bmc, bound=0] -// BMC: error: verification failed: checked_wrong [{{.*}}::unreachable@ -// BMC: error: verification failed: aborts [{{.*}}::unreachable@ +// BMC: error: verification failed: checked_wrong [unreachable] +// BMC: error: verification failed: aborts [unreachable] // VCR-LABEL: fn aborts // VCR: {{^ +}}if{{$}} From 5252a75aaf2afa9a4c75a78b927c6bf3e1d8a45c Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:34 +0530 Subject: [PATCH 047/259] test: Expect failures as Clang diagnostics in backend_model_names.cpp. --- clang/test/Verify/suite/backend_model_names.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/backend_model_names.cpp b/clang/test/Verify/suite/backend_model_names.cpp index fc90bb19bd..a0bc20de6d 100644 --- a/clang/test/Verify/suite/backend_model_names.cpp +++ b/clang/test/Verify/suite/backend_model_names.cpp @@ -9,8 +9,8 @@ unsigned renamed_parameter(unsigned implementation_name) { } // CHECK: error: verification failed: renamed_parameter -// CHECK-SAME: implementation_name [ssa=interface_name_0] [type=u32] // CHECK-SAME: [reason=counterexample] +// CHECK: note: counterexample: implementation_name = 0, result = 1 // JSON: "name":"implementation_name" // JSON-SAME: "sort":"u32" From 72ce7bad16441189547f0e0a0b4b7412f7c96558 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:34 +0530 Subject: [PATCH 048/259] test: Expect failures as Clang diagnostics in backend_model_truth.cpp. --- clang/test/Verify/suite/backend_model_truth.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/backend_model_truth.cpp b/clang/test/Verify/suite/backend_model_truth.cpp index cc96d9393d..b087633dae 100644 --- a/clang/test/Verify/suite/backend_model_truth.cpp +++ b/clang/test/Verify/suite/backend_model_truth.cpp @@ -11,8 +11,8 @@ int underdetermined_model(int value, bool take_value) } // CHECK: error: verification failed: underdetermined_model -// CHECK-SAME: value [ssa=value_0] [type=i32] = // CHECK-SAME: [backend=z3] [reason=counterexample] +// CHECK: note: counterexample: value = , take_value = false, result = 0 // JSON: "model":[ // JSON-SAME: {"name":"value","sort":"i32" From 78d83456d95f58e283332bb282b0d8136d1b0079 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:35 +0530 Subject: [PATCH 049/259] test: Expect failures as Clang diagnostics in backend_model_values.cpp. --- clang/test/Verify/suite/backend_model_values.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/backend_model_values.cpp b/clang/test/Verify/suite/backend_model_values.cpp index 2406c80e26..28bd5a9ea7 100644 --- a/clang/test/Verify/suite/backend_model_values.cpp +++ b/clang/test/Verify/suite/backend_model_values.cpp @@ -13,6 +13,6 @@ unsigned maximum_result() } // CHECK: error: verification failed: negative_result -// CHECK-SAME: result [ssa=__result_1] [type=i32] = -1 +// CHECK: note: counterexample: result = -1 // CHECK: error: verification failed: maximum_result -// CHECK-SAME: result [ssa=__result_1] [type=u32] = 4294967295 +// CHECK: note: counterexample: result = 4294967295 From 9872d5e766687596f07d78d51b80ee81f5d8ad36 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:35 +0530 Subject: [PATCH 050/259] test: Expect failures as Clang diagnostics in backend_result_contract.cpp. --- clang/test/Verify/suite/backend_result_contract.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/backend_result_contract.cpp b/clang/test/Verify/suite/backend_result_contract.cpp index 80cf21c00a..e2b3408ad6 100644 --- a/clang/test/Verify/suite/backend_result_contract.cpp +++ b/clang/test/Verify/suite/backend_result_contract.cpp @@ -20,11 +20,11 @@ int invalid_result() } // Z3-DAG: Verified: valid_result [backend=z3] -// Z3: backend_result_contract.cpp:{{[0-9]+}}:{{[0-9]+}}: error: verification failed: invalid_result [{{.*}}::postcondition@{{[0-9]+}}:{{[0-9]+}}] +// Z3: backend_result_contract.cpp:{{[0-9]+}}:{{[0-9]+}}: error: verification failed: invalid_result [postcondition] // Z3-SAME: [backend=z3] [reason=counterexample] // BMC-DAG: Verified: valid_result [backend=bmc, bound=0] -// BMC: backend_result_contract.cpp:{{[0-9]+}}:{{[0-9]+}}: error: verification failed: invalid_result [{{.*}}::postcondition@{{[0-9]+}}:{{[0-9]+}}] +// BMC: backend_result_contract.cpp:{{[0-9]+}}:{{[0-9]+}}: error: verification failed: invalid_result [postcondition] // BMC-SAME: [backend=bmc, bound=0] [reason=counterexample] // LOWER-DAG: Lowered: valid_result From f43f335bcbc289b7a7d5d1d8d92170bef9274c4b Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:36 +0530 Subject: [PATCH 051/259] test: Expect failures as Clang diagnostics in backend_stable_id.test. --- clang/test/Verify/suite/backend_stable_id.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/backend_stable_id.test b/clang/test/Verify/suite/backend_stable_id.test index 9765d12491..5a20da88ad 100644 --- a/clang/test/Verify/suite/backend_stable_id.test +++ b/clang/test/Verify/suite/backend_stable_id.test @@ -6,7 +6,7 @@ # RUN: not %cpp-verify --diagnostics-format=json %S/Inputs/backend_inlined_source.cpp -- 2>&1 | FileCheck %s --check-prefix=INLINED # RUN: not %cpp-verify %S/Inputs/backend_stable_id_suffix.cpp -- 2>&1 | FileCheck %s --check-prefix=SUFFIX -# CHECK: verification failed: stable_identity [{{.*}}::postcondition@2:37] +# CHECK: verification failed: stable_identity [postcondition] # INLINED: "function":"inlined_source" # INLINED-SAME: "id":"{{.*}}::postcondition@4:19" # INLINED-SAME: "end_column":37 @@ -14,4 +14,4 @@ # The suffix separates obligations of one kind at one anchor: here both # preconditions of the callee are checked at the call. -# SUFFIX: verification failed: two_preconditions [{{.*}}::precondition@10:3#2] +# SUFFIX: verification failed: two_preconditions [precondition] From a2d16a49dece8a22eecc648b55c5064a35c6aa72 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:36 +0530 Subject: [PATCH 052/259] test: Expect failures as Clang diagnostics in behaviors.cpp. --- clang/test/Verify/suite/behaviors.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/test/Verify/suite/behaviors.cpp b/clang/test/Verify/suite/behaviors.cpp index 7f97694738..aec988869d 100644 --- a/clang/test/Verify/suite/behaviors.cpp +++ b/clang/test/Verify/suite/behaviors.cpp @@ -32,7 +32,7 @@ int calls_with_minimum(int y) { return abs_value(y); } -// CHECK-DAG: error: verification failed: calls_with_minimum [{{.*}}::precondition@[[@LINE-2]]:3] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: calls_with_minimum [precondition] int sign(int x) cppverify::behavior(positive, x > 0) @@ -43,7 +43,7 @@ int sign(int x) { return x > 0 ? 1 : (x < 0 ? -1 : 0); } -// CHECK-DAG: error: verification failed: sign [{{.*}}::assertion@[[@LINE-4]]:3] +// CHECK-DAG: :[[@LINE-4]]:3: error: verification failed: sign [assertion] int clamp(int x) cppverify::behavior(low, x <= 0) @@ -54,7 +54,7 @@ int clamp(int x) { return x; } -// CHECK-DAG: error: verification failed: clamp [{{.*}}::assertion@[[@LINE-4]]:3] +// CHECK-DAG: :[[@LINE-4]]:3: error: verification failed: clamp [assertion] int small_zero(int x) cppverify::behavior(small, x < 10) @@ -62,7 +62,7 @@ int small_zero(int x) { return x < 5 ? 0 : 1; } -// CHECK-DAG: error: verification failed: small_zero [{{.*}}::postcondition@[[@LINE-4]]:21] +// CHECK-DAG: :[[@LINE-4]]:21: error: verification failed: small_zero [postcondition] // A behavior's assumption reads memory at entry. void bump(int *p) From 98f3c63f0c84871aae3c5cbade718f3808990103 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:37 +0530 Subject: [PATCH 053/259] test: Expect failures as Clang diagnostics in bmc_incremental.cpp. --- clang/test/Verify/suite/bmc_incremental.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/bmc_incremental.cpp b/clang/test/Verify/suite/bmc_incremental.cpp index e10f9e1092..b023b37a56 100644 --- a/clang/test/Verify/suite/bmc_incremental.cpp +++ b/clang/test/Verify/suite/bmc_incremental.cpp @@ -57,10 +57,11 @@ int open_frontier(int limit) // TEXT: Verified: completes_at_two [backend=bmc, bound=2] // TEXT-SAME: [bounds=0,1,2] [reused-queries={{[1-9][0-9]*}}] // TEXT: error: verification failed: bug_on_second_iteration -// TEXT-SAME: trace: loop.iteration 1 -// TEXT-SAME: -> loop.iteration 2 // TEXT-SAME: [backend=bmc, bound=2] // TEXT-SAME: [bounds=0,1,2] [reused-queries={{[1-9][0-9]*}}] +// TEXT: note: counterexample: index = 0 -> 1 +// TEXT: note: runs iteration 1 of the loop +// TEXT: note: runs iteration 2 of the loop // TEXT: BoundedSafe: open_frontier [backend=bmc, bound=4] // TEXT-SAME: [reason=bmc.incomplete-bound] // TEXT-SAME: [bounds=0,1,2,3,4] [reused-queries={{[1-9][0-9]*}}] From c944cc124c75d24cc9cab2f7e9d692a3a21e975f Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:37 +0530 Subject: [PATCH 054/259] test: Expect failures as Clang diagnostics in bounds_single_object.cpp. --- clang/test/Verify/suite/bounds_single_object.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/bounds_single_object.cpp b/clang/test/Verify/suite/bounds_single_object.cpp index 4c2b1e0769..ff86d9880a 100644 --- a/clang/test/Verify/suite/bounds_single_object.cpp +++ b/clang/test/Verify/suite/bounds_single_object.cpp @@ -4,7 +4,7 @@ // Without a valid(p, n) declaration a pointer addresses a single object, so // p[i] is in bounds only at i == 0. --no-check-ub turns memory checking off. int get(int* p, int i) cppverify::pre(p != nullptr && i >= 0) cppverify::post(cppverify::result == p[i]) { return p[i]; } -// CHECKED: error: verification failed: get [{{.*}}::bounds@ +// CHECKED: error: verification failed: get [bounds] // UNCHECKED: Verified: get int first(int* p) cppverify::pre(p != nullptr) cppverify::post(cppverify::result == p[0]) { return p[0]; } From 5dd960ca0f14f20ca44cd0e09affdecabb538ff4 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:38 +0530 Subject: [PATCH 055/259] test: Expect failures as Clang diagnostics in calls_in_expressions.cpp. --- clang/test/Verify/suite/calls_in_expressions.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/clang/test/Verify/suite/calls_in_expressions.cpp b/clang/test/Verify/suite/calls_in_expressions.cpp index 223ac0b3ef..d3f40e6453 100644 --- a/clang/test/Verify/suite/calls_in_expressions.cpp +++ b/clang/test/Verify/suite/calls_in_expressions.cpp @@ -153,7 +153,7 @@ int unguarded(int x) return 1; return 0; } -// CHECK: error: verification failed: unguarded {{.*}}precondition@[[@LINE-4]]:7 +// CHECK: :[[@LINE-4]]:7: error: verification failed: unguarded [precondition] int either(int x) cv::pre(-2000 <= x && x <= 2000) @@ -180,7 +180,7 @@ int choose_wrong(bool c, int x) int y = c ? inc(x) : sq(x); return y; } -// CHECK: error: verification failed: choose_wrong {{.*}}precondition@[[@LINE-3]]:15 +// CHECK: :[[@LINE-3]]:15: error: verification failed: choose_wrong [precondition] int count_up(int n) cv::pre(0 <= n && n < 100) @@ -250,7 +250,7 @@ int count_past(int n) } return i; } -// CHECK: error: verification failed: count_past {{.*}}precondition@[[@LINE-8]]:10 +// CHECK: :[[@LINE-8]]:10: error: verification failed: count_past [precondition] // A call's result is its postcondition's, not any value. int wrong(int x) @@ -395,7 +395,8 @@ int classify_wrong(int x) return 1; return 0; } -// CHECK: error: verification failed: classify_wrong {{.*}}postcondition{{.*}}x [ssa=x_0] [type=i32] = 5 +// CHECK: error: verification failed: classify_wrong {{.*}}postcondition +// CHECK: note: counterexample: {{.*}}x = 5{{( ->|,|$)}} int *first_of(int *a) cv::pre(cv::valid(a, 2)) From 3c6ba1e17e440f0c149decfcf4b4e75fb2a1f168 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:38 +0530 Subject: [PATCH 056/259] test: Expect failures as Clang diagnostics in certified_counterexamples.cpp. --- clang/test/Verify/suite/certified_counterexamples.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/clang/test/Verify/suite/certified_counterexamples.cpp b/clang/test/Verify/suite/certified_counterexamples.cpp index ad216a1f98..3ea7c56b99 100644 --- a/clang/test/Verify/suite/certified_counterexamples.cpp +++ b/clang/test/Verify/suite/certified_counterexamples.cpp @@ -95,10 +95,13 @@ int masked_wrong(int x) // CHECK-DAG: Unresolved: hidden_recursive [backend={{z3|bmc, bound=0}}] [reason=spec.hidden] // Z3-DAG: Verified: bounded_closed_form [backend=z3] // BMC-DAG: Verified: bounded_closed_form [backend=bmc -// CHECK-DAG: verification failed: bounded_closed_form_wrong {{.*}}n [ssa=n_0] [type=i32] = 33; +// CHECK-DAG: verification failed: bounded_closed_form_wrong +// CHECK-DAG: note: counterexample: {{.*}}n = 33{{( ->|,|$)}} // CHECK-DAG: Unresolved: scaled_true [backend={{z3|bmc, bound=0}}] [reason=spec.hidden] -// CHECK-DAG: verification failed: scaled_wrong {{.*}}x [ssa=x_0] [type=u32] = 3000000000; -// CHECK-DAG: verification failed: masked_wrong {{.*}}x [ssa=x_0] [type=i32] = 700; +// CHECK-DAG: verification failed: scaled_wrong +// CHECK-DAG: note: counterexample: {{.*}}x = 3000000000{{( ->|,|$)}} +// CHECK-DAG: verification failed: masked_wrong +// CHECK-DAG: note: counterexample: {{.*}}x = 700{{( ->|,|$)}} // JSON-DAG: "function":"hidden_true"{{.*}}"reason":"spec.hidden" // JSON-DAG: "function":"hidden_false"{{.*}}"reason":"counterexample" From 1213b5f4ac8eba4927eaf80eb008adc373b68597 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:39 +0530 Subject: [PATCH 057/259] test: Expect failures as Clang diagnostics in certified_counterexamples_cvc5.test. --- .../Verify/suite/certified_counterexamples_cvc5.test | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/clang/test/Verify/suite/certified_counterexamples_cvc5.test b/clang/test/Verify/suite/certified_counterexamples_cvc5.test index d0c4ed88c8..5cb587d3f9 100644 --- a/clang/test/Verify/suite/certified_counterexamples_cvc5.test +++ b/clang/test/Verify/suite/certified_counterexamples_cvc5.test @@ -16,7 +16,10 @@ # CVC5-DAG: verification failed: masked_wrong {{.*}}[backend=cvc5] # PORTFOLIO-DAG: Unresolved: hidden_true [backend=portfolio] [reason=spec.hidden] -# PORTFOLIO-DAG: verification failed: hidden_false {{.*}}x [ssa=x_0] +# PORTFOLIO-DAG: verification failed: hidden_false +# PORTFOLIO-DAG: note: counterexample: {{.*}}x = # PORTFOLIO-DAG: Verified: bounded_closed_form [backend=portfolio] -# PORTFOLIO-DAG: verification failed: scaled_wrong {{.*}}x [ssa=x_0] [type=u32] = 3000000000; -# PORTFOLIO-DAG: verification failed: masked_wrong {{.*}}x [ssa=x_0] [type=i32] = 700; +# PORTFOLIO-DAG: verification failed: scaled_wrong +# PORTFOLIO-DAG: note: counterexample: {{.*}}x = 3000000000{{( ->|,|$)}} +# PORTFOLIO-DAG: verification failed: masked_wrong +# PORTFOLIO-DAG: note: counterexample: {{.*}}x = 700{{( ->|,|$)}} From f7e5de827c8a7865811ce71689ad1b5a7a6cd0c9 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:39 +0530 Subject: [PATCH 058/259] test: Expect failures as Clang diagnostics in certified_failure_attribution.cpp. --- clang/test/Verify/suite/certified_failure_attribution.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/certified_failure_attribution.cpp b/clang/test/Verify/suite/certified_failure_attribution.cpp index 25a0377b2b..463842f6f0 100644 --- a/clang/test/Verify/suite/certified_failure_attribution.cpp +++ b/clang/test/Verify/suite/certified_failure_attribution.cpp @@ -35,5 +35,5 @@ void break_heap_wrong(int *p) i = i + 1; } } -// CHECK: error: verification failed: break_heap_wrong [{{.*}}::postcondition@23:24] {{.*}}[reason=counterexample] +// CHECK: :23:24: error: verification failed: break_heap_wrong [postcondition] {{.*}}[reason=counterexample] // CHECK-NOT: within_seconds From 27de023b97063c2dd1496fc879bc9487cf550661 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:40 +0530 Subject: [PATCH 059/259] test: Expect failures as Clang diagnostics in certified_quantifier_ranges.cpp. --- .../Verify/suite/certified_quantifier_ranges.cpp | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/clang/test/Verify/suite/certified_quantifier_ranges.cpp b/clang/test/Verify/suite/certified_quantifier_ranges.cpp index 737522d962..6092e4a818 100644 --- a/clang/test/Verify/suite/certified_quantifier_ranges.cpp +++ b/clang/test/Verify/suite/certified_quantifier_ranges.cpp @@ -75,12 +75,13 @@ int first_positive_bitwise(const int *p, int n) return p[0]; } -// CHECK-DAG: verification failed: first_positive_squared_wide [{{.*}}::postcondition@ -// CHECK-DAG: verification failed: first_positive [{{.*}}::postcondition@ -// CHECK-DAG: verification failed: first_positive_long [{{.*}}::postcondition@{{.*}}n [ssa=n_0] [type=i32] = 2000000 -// CHECK-DAG: verification failed: writes_first [{{.*}}::postcondition@ -// CHECK-DAG: verification failed: first_positive_indexed [{{.*}}::postcondition@ -// CHECK-DAG: verification failed: first_positive_squared [{{.*}}::postcondition@ +// CHECK-DAG: verification failed: first_positive_squared_wide [postcondition] +// CHECK-DAG: verification failed: first_positive [postcondition] +// CHECK-DAG: verification failed: first_positive_long [postcondition] +// CHECK-DAG: note: counterexample: {{.*}}n = 2000000{{( ->|,|$)}} +// CHECK-DAG: verification failed: writes_first [postcondition] +// CHECK-DAG: verification failed: first_positive_indexed [postcondition] +// CHECK-DAG: verification failed: first_positive_squared [postcondition] // CHECK-DAG: Unresolved: first_positive_bitwise [backend=z3] [reason=counterexample.unchecked] // CHECK-DAG: a quantifier range of {{[0-9]+}} values is too wide to expand From 6c717782695934d44a552f6d7f31aec479821d7e Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:40 +0530 Subject: [PATCH 060/259] test: Expect failures as Clang diagnostics in choose.cpp. --- clang/test/Verify/suite/choose.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/choose.cpp b/clang/test/Verify/suite/choose.cpp index a20dcceed6..423331fdf2 100644 --- a/clang/test/Verify/suite/choose.cpp +++ b/clang/test/Verify/suite/choose.cpp @@ -44,13 +44,13 @@ void claims_one() cppverify::post(pick() == 1) { } -// CHECK-DAG: error: verification failed: claims_one [{{.*}}::postcondition@{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: claims_one [postcondition]{{.*}}[reason=counterexample] void no_witness() { cppverify::check(cppverify::choose(x, x * x == 2) == 0); } -// CHECK-DAG: error: verification failed: no_witness [{{.*}}::assertion@{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: no_witness [assertion]{{.*}}[reason=counterexample] // In ghost code a choice is stored like any mathematical value: the store // must fit, which the range guarantees when a witness exists. From fc2200b63c398bed6aa45abd7341008b12f727dd Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:41 +0530 Subject: [PATCH 061/259] test: Expect failures as Clang diagnostics in choose_axioms.cpp. --- clang/test/Verify/suite/choose_axioms.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/clang/test/Verify/suite/choose_axioms.cpp b/clang/test/Verify/suite/choose_axioms.cpp index 01b001304e..1bc600f893 100644 --- a/clang/test/Verify/suite/choose_axioms.cpp +++ b/clang/test/Verify/suite/choose_axioms.cpp @@ -40,7 +40,7 @@ cppverify::proof void odd_chosen_at_4() cppverify::post(odd_chosen(4)) { } -// CHECK-DAG: error: verification failed: odd_chosen_at_4 [{{.*}}::postcondition@{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: odd_chosen_at_4 [postcondition]{{.*}}[reason=counterexample] // In the postcondition of a hidden spec. cppverify::spec int parity(int n) @@ -63,7 +63,7 @@ cppverify::proof void parity_of_7_wrong(int x) { cppverify::hide(parity); } -// CHECK-DAG: error: verification failed: parity_of_7_wrong [{{.*}}::postcondition@{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: parity_of_7_wrong [postcondition]{{.*}}[reason=counterexample] // A choose that reads memory is read where its application is. cppverify::spec int low_bit(const int *a) @@ -90,7 +90,7 @@ void set_one_wrong(int *a) cppverify::hide(low_bit); a[0] = 1; } -// CHECK-DAG: error: verification failed: set_one_wrong [{{.*}}::postcondition@{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: set_one_wrong [postcondition]{{.*}}[reason=counterexample] cppverify::spec int low_bit_rec(const int *a, int n) cppverify::decreases(n) @@ -130,7 +130,7 @@ int max_index_wrong(const int *a, int n, int m) { return m; } -// CHECK-DAG: error: verification failed: max_index_wrong [{{.*}}::postcondition@{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: max_index_wrong [postcondition]{{.*}}[reason=counterexample] // In the induction hypothesis of a recursive spec. cppverify::spec int bit(int n) @@ -191,4 +191,4 @@ cppverify::proof void parity_sum_5_wrong(int x) cppverify::post(parity_sum(x) == 2) { } -// CHECK-DAG: error: verification failed: parity_sum_5_wrong [{{.*}}::postcondition@{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: parity_sum_5_wrong [postcondition]{{.*}}[reason=counterexample] From 74f86931adfd798bec2b93280df6c6777b6149c6 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:41 +0530 Subject: [PATCH 062/259] test: Expect failures as Clang diagnostics in choose_identity.cpp. --- clang/test/Verify/suite/choose_identity.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/clang/test/Verify/suite/choose_identity.cpp b/clang/test/Verify/suite/choose_identity.cpp index 46efc598de..ed0d329c7d 100644 --- a/clang/test/Verify/suite/choose_identity.cpp +++ b/clang/test/Verify/suite/choose_identity.cpp @@ -45,13 +45,15 @@ cv::proof void other_condition(int n) cv::post(cv::choose(k, k > n) == cv::choose(k, k >= n)) { } -// CHECK-DAG: error: verification failed: other_condition [{{.*}}] (counterexample: +// CHECK-DAG: error: verification failed: other_condition [postcondition] +// CHECK-DAG: note: counterexample: cv::proof void other_value(int n, int m) cv::post(cv::choose(k, k > n) == cv::choose(k, k > m)) { } -// CHECK-DAG: error: verification failed: other_value [{{.*}}] (counterexample: +// CHECK-DAG: error: verification failed: other_value [postcondition] +// CHECK-DAG: note: counterexample: cv::proof void other_range() cv::post(cv::choose(k, 0, 10, k >= 0) == cv::choose(k, 0, 11, k >= 0)) @@ -98,7 +100,8 @@ void write_inside(int *a, int n, int x) { a[0] = x == 0 ? 1 : 0; } -// CHECK-DAG: error: verification failed: write_inside [{{.*}}] (counterexample: +// CHECK-DAG: choose_identity.cpp:[[@LINE-5]]:{{[0-9]+}}: error: verification failed: write_inside [postcondition]{{.*}}[reason=counterexample] +// CHECK-DAG: choose_identity.cpp:[[@LINE-6]]:{{[0-9]+}}: note: counterexample: a = // Which cells c[a[k]] reads depends on memory too: each read compares what it // reads in each memory, its address included, so the write to b keeps it. From 990222d8e0eda86a0a7f21e41071eefcf6daf844 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:42 +0530 Subject: [PATCH 063/259] test: Expect failures as Clang diagnostics in choose_reads.cpp. --- clang/test/Verify/suite/choose_reads.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/choose_reads.cpp b/clang/test/Verify/suite/choose_reads.cpp index 86f72c1d4d..b80508c344 100644 --- a/clang/test/Verify/suite/choose_reads.cpp +++ b/clang/test/Verify/suite/choose_reads.cpp @@ -61,4 +61,4 @@ void set_inside(int *a, int n, int x) { a[0] = x == 0 ? 1 : 0; } -// CHECK-DAG: error: verification failed: set_inside [{{.*}}::postcondition@[[@LINE-4]]:30] +// CHECK-DAG: :[[@LINE-4]]:30: error: verification failed: set_inside [postcondition] From 18284774f631855c8ed17d1d100038d4057b01c0 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:42 +0530 Subject: [PATCH 064/259] test: Expect failures as Clang diagnostics in choose_recursion.cpp. --- clang/test/Verify/suite/choose_recursion.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/clang/test/Verify/suite/choose_recursion.cpp b/clang/test/Verify/suite/choose_recursion.cpp index bf5eb368ca..31eef0e5b2 100644 --- a/clang/test/Verify/suite/choose_recursion.cpp +++ b/clang/test/Verify/suite/choose_recursion.cpp @@ -25,7 +25,8 @@ cppverify::spec int stuck(int n) { return n <= 0 ? 0 : stuck(n - 1) + cppverify::choose(k, n == 1 ? k == stuck(n) + 1 : k == 0); } -// CHECK-DAG: error: spec decreases failed: stuck [backend=z3] [reason=counterexample] (n [type=math-i32] = 1) +// CHECK-DAG: error: spec decreases failed: stuck [backend=z3] [reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}n = 1{{( ->|,|$)}} // The same with a postcondition, which is proved with termination. cppverify::spec int stuck_post(int n) @@ -34,7 +35,8 @@ cppverify::spec int stuck_post(int n) { return n <= 0 ? 0 : cppverify::choose(k, n == 1 ? k == stuck_post(n) + 1 : k == 0); } -// CHECK-DAG: error: spec decreases and post failed: stuck_post [backend=z3] [reason=counterexample] (n [type=math-i32] = 1) +// CHECK-DAG: error: spec decreases and post failed: stuck_post [backend=z3] [reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}n = 1{{( ->|,|$)}} // The axiom of a choose holds where its applications lower the measure, // which places the choice in [0, n). @@ -51,7 +53,8 @@ cppverify::spec int unbounded(int n) { return n <= 0 ? 0 : cppverify::choose(k, unbounded(k) == 0); } -// CHECK-DAG: error: spec decreases failed: unbounded [backend=z3] [reason=counterexample] (n [type=math-i32] = {{[1-9][0-9]*}}) +// CHECK-DAG: error: spec decreases failed: unbounded [backend=z3] [reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}n = {{[1-9][0-9]*}}{{( ->|,|$)}} int forty_two(int x) cppverify::post(cppverify::result == 42) From 47b90b10500369ec92020d967d8220d96637a566 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:43 +0530 Subject: [PATCH 065/259] test: Expect failures as Clang diagnostics in class_invariants.cpp. --- clang/test/Verify/suite/class_invariants.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/clang/test/Verify/suite/class_invariants.cpp b/clang/test/Verify/suite/class_invariants.cpp index 293be0b1a2..5d1be26497 100644 --- a/clang/test/Verify/suite/class_invariants.cpp +++ b/clang/test/Verify/suite/class_invariants.cpp @@ -103,8 +103,8 @@ class Ring { // CHECK-DAG: Verified: Ring::size [backend=z3] // CHECK-DAG: Verified: Ring::rotate [backend=z3] // CHECK-DAG: Verified: Ring::set_head [backend=z3] -// CHECK-DAG: error: verification failed: Ring::skip [{{.*}}::type-invariant@ -// CHECK-DAG: error: verification failed: Ring::peek_broken [{{.*}}::type-invariant@ +// CHECK-DAG: error: verification failed: Ring::skip [type-invariant] +// CHECK-DAG: error: verification failed: Ring::peek_broken [type-invariant] // A constructor that does not establish the invariant. class Window { @@ -117,7 +117,7 @@ class Window { cppverify::type_invariant(0 <= first && first < 100); }; -// CHECK-DAG: error: verification failed: Window::Window [{{.*}}::type-invariant@ +// CHECK-DAG: error: verification failed: Window::Window [type-invariant] class Bounded { public: @@ -170,7 +170,7 @@ int ring_value() int v = r.pop(); return v; } -// CHECK-DAG: error: verification failed: ring_value [{{.*}}::postcondition@ +// CHECK-DAG: error: verification failed: ring_value [postcondition] int broken_by_caller() cppverify::post(true) @@ -179,7 +179,7 @@ int broken_by_caller() b.first = 500; return b.get(); } -// CHECK-DAG: error: verification failed: broken_by_caller [{{.*}}::type-invariant@[[@LINE-2]] +// CHECK-DAG: :[[@LINE-2]]:{{[0-9]+}}: error: verification failed: broken_by_caller [type-invariant] // An extent in a class invariant: on entry `this->data` points to `len` // elements, as a pointer field's extent in a precondition does. At exit the @@ -234,4 +234,4 @@ int grown(const int *p, int n) int x = v.first(); return x; } -// CHECK-DAG: error: verification failed: grown [{{.*}}::bounds@[[@LINE-3]] +// CHECK-DAG: :[[@LINE-3]]:{{[0-9]+}}: error: verification failed: grown [bounds] From 7992fd28e41de3ad3b9ccc1df26f6435f25558e5 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:43 +0530 Subject: [PATCH 066/259] test: Expect failures as Clang diagnostics in class_templates.cpp. --- clang/test/Verify/suite/class_templates.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/class_templates.cpp b/clang/test/Verify/suite/class_templates.cpp index c59e3aaa2b..8035283f81 100644 --- a/clang/test/Verify/suite/class_templates.cpp +++ b/clang/test/Verify/suite/class_templates.cpp @@ -82,9 +82,9 @@ signed char twice_char() // CHECK-DAG: Verified: Box::twice [backend=z3] // CHECK-DAG: Verified: twice_int [backend=z3] // CHECK-DAG: Verified: Box::Box [backend=z3] -// CHECK-DAG: error: verification failed: Box::twice [{{.*}}::postcondition@ +// CHECK-DAG: error: verification failed: Box::twice [postcondition] // NOTE: error: verification failed: Box::twice -// NOTE-NEXT: class_templates.cpp:[[@LINE-8]]:21: note: in instantiation of member function 'Box::twice' requested here +// NOTE: class_templates.cpp:[[@LINE-8]]:21: note: in instantiation of member function 'Box::twice' requested here // An out-of-line definition with a contract, explicitly instantiated. template From 6613f1c1f190db6ac049e9df77fc366ea00fde02 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:44 +0530 Subject: [PATCH 067/259] test: Expect failures as Clang diagnostics in collections.cpp. --- clang/test/Verify/suite/collections.cpp | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/clang/test/Verify/suite/collections.cpp b/clang/test/Verify/suite/collections.cpp index fd2d88e85a..1af454789b 100644 --- a/clang/test/Verify/suite/collections.cpp +++ b/clang/test/Verify/suite/collections.cpp @@ -32,7 +32,8 @@ cppverify::proof void set_wrong(set a, int x) { cppverify::check(a.contains(x)); } -// CHECK-DAG: error: verification failed: set_wrong [{{.*}}::assertion@[[@LINE-2]]:3] (counterexample: a [ssa=a_0] [type=set] = {{{.*}}}{{.*}}) [backend=z3] [reason=counterexample] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: set_wrong [assertion] [backend=z3] [reason=counterexample] +// CHECK-DAG: note: counterexample: a = {{{.*}}}{{.*}} cppverify::proof void multisets(multiset m, int x) { @@ -48,7 +49,7 @@ cppverify::proof void multiset_wrong(multiset m, int x) { cppverify::check(m.remove(x).insert(x) == m); } -// CHECK-DAG: error: verification failed: multiset_wrong [{{.*}}::assertion@[[@LINE-2]]:3] (counterexample: {{.*}}) [backend=z3] [reason=counterexample] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: multiset_wrong [assertion] [backend=z3] [reason=counterexample] cppverify::proof void maps(map m, int k, int v, int j) cppverify::pre(k != j) @@ -67,21 +68,24 @@ cppverify::proof void map_wrong(map m, int k) { cppverify::check(m.insert(k, 1).remove(k) == m); } -// CHECK-DAG: error: verification failed: map_wrong [{{.*}}::assertion@[[@LINE-2]]:3] (counterexample: {{.*}}m [ssa=m_0] [type=map] = {{{.*}} -> {{.*}}}) [backend=z3] [reason=counterexample] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: map_wrong [assertion] [backend=z3] [reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}m = {{{.*}} -> {{.*}}} // A set may hold every integer; the certifier checks the infinite one. cppverify::proof void some_outside(set a) { cppverify::check(cppverify::exists(k, !a.contains(k))); } -// CHECK-DAG: error: verification failed: some_outside [{{.*}}::assertion@[[@LINE-2]]:3] (counterexample: a [ssa=a_0] [type=set] = {..}) [backend=z3] [reason=counterexample] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: some_outside [assertion] [backend=z3] [reason=counterexample] +// CHECK-DAG: note: counterexample: a = {..} cppverify::proof void map_values(map m) cppverify::pre(m.contains(5)) { cppverify::check(cppverify::forall(k, m[k] == 0)); } -// CHECK-DAG: error: verification failed: map_values [{{.*}}::assertion@[[@LINE-2]]:3] (counterexample: m [ssa=m_0] [type=map] = {{{.*}}5{{.*}}}) [backend=z3] [reason=counterexample] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: map_values [assertion] [backend=z3] [reason=counterexample] +// CHECK-DAG: note: counterexample: m = {{{.*}}5{{.*}}} cppverify::spec bool valid(const int *p, int n) { return true; } From 41ba7d142bf597177b49a7b3897c26180d184f8c Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:44 +0530 Subject: [PATCH 068/259] test: Expect failures as Clang diagnostics in command_line.cpp. --- clang/test/Verify/suite/command_line.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/command_line.cpp b/clang/test/Verify/suite/command_line.cpp index 9c7b6a5579..10b71413e6 100644 --- a/clang/test/Verify/suite/command_line.cpp +++ b/clang/test/Verify/suite/command_line.cpp @@ -64,7 +64,7 @@ int first(const int *p) // DEFAULT-NEXT: Verified: down_zero [backend=z3] // DEFAULT-NEXT: Verified: add_one [backend=z3] // DEFAULT-NEXT: error: verification failed: add_two -// DEFAULT-NEXT: Trusted: clamp +// DEFAULT: Trusted: clamp // DEFAULT-NEXT: Verified: first [backend=z3] // DEFAULT-NEXT: Summary: 4 verified, 1 failed, 1 unresolved (construct.unsupported 1), 1 trusted in {{[0-9]+\.[0-9]}} s // DEFAULT-NOT: {{.}} @@ -72,7 +72,7 @@ int first(const int *p) // QUIET: error: lookup: goto is unsupported // QUIET: error: lookup: labels are unsupported // QUIET: error: verification failed: add_two -// QUIET-NEXT: Summary: 4 verified, 1 failed, 1 unresolved (construct.unsupported 1), 1 trusted in +// QUIET: Summary: 4 verified, 1 failed, 1 unresolved (construct.unsupported 1), 1 trusted in // VERBOSE: Verified: spec axiom: twice // VERBOSE-NEXT: Verified: spec decreases: down From 5b909eead7b9c9fa705744b07dc04004cefb8b3d Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:45 +0530 Subject: [PATCH 069/259] test: Expect failures as Clang diagnostics in constant_expressions.cpp. --- clang/test/Verify/suite/constant_expressions.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/constant_expressions.cpp b/clang/test/Verify/suite/constant_expressions.cpp index 3d4507fffa..18d789dd67 100644 --- a/clang/test/Verify/suite/constant_expressions.cpp +++ b/clang/test/Verify/suite/constant_expressions.cpp @@ -32,4 +32,5 @@ int facts_wrong(int x) __is_same(int, long) + (offsetof(Pair, second) == 0) + (__builtin_LINE() == __LINE__ + 1); } -// CHECK-DAG: error: verification failed: facts_wrong [{{.*}}::postcondition@{{.*}}result [ssa=__result_1] [type=i32] = 2{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: facts_wrong [postcondition] {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}result = 2{{( ->|,|$)}} From a01794d436df81d6ed7138f35054d1ff6aa24fcb Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:45 +0530 Subject: [PATCH 070/259] test: Expect failures as Clang diagnostics in constructors.cpp. --- clang/test/Verify/suite/constructors.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/constructors.cpp b/clang/test/Verify/suite/constructors.cpp index 3a46c95158..17cdb271e7 100644 --- a/clang/test/Verify/suite/constructors.cpp +++ b/clang/test/Verify/suite/constructors.cpp @@ -85,7 +85,7 @@ struct Partial { int n; int limit; }; -// CHECK-DAG: error: verification failed: Partial::Partial [{{.*}}::initialization@[[@LINE-3]]:7] +// CHECK-DAG: :[[@LINE-3]]:7: error: verification failed: Partial::Partial [initialization] // Members are initialized in declaration order, whatever the order of the // initializers: `n` reads `limit` before it is initialized. @@ -97,7 +97,7 @@ struct Early { int n; int limit; }; -// CHECK-DAG: error: verification failed: Early::Early [{{.*}}::initialization@ +// CHECK-DAG: error: verification failed: Early::Early [initialization] // The in-class initializers of the members a constructor does not name run // in their place. From 4812a6a0d1c45cc81e1b2cb9d57c3e45733c935f Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:46 +0530 Subject: [PATCH 071/259] test: Expect failures as Clang diagnostics in contract_math.cpp. --- clang/test/Verify/suite/contract_math.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/clang/test/Verify/suite/contract_math.cpp b/clang/test/Verify/suite/contract_math.cpp index 354b4fa2bf..d95c7c6c48 100644 --- a/clang/test/Verify/suite/contract_math.cpp +++ b/clang/test/Verify/suite/contract_math.cpp @@ -13,7 +13,8 @@ unsigned add_wraps(unsigned a, unsigned b) { return a + b; } -// CHECK-DAG: error: verification failed: add_wraps [{{.*}}::postcondition@{{.*}}b [ssa=b_0] [type=u32] = +// CHECK-DAG: error: verification failed: add_wraps [postcondition] +// CHECK-DAG: note: counterexample: {{.*}}b = unsigned add_mod(unsigned a, unsigned b) cppverify::post(cppverify::result == (a + b) % 4294967296) @@ -51,7 +52,7 @@ bool is_max(unsigned u) return u == 4294967295u; } // CHECK-DAG: warning: contract arithmetic is mathematical: the negative value -1 keeps its value here instead of converting to unsigned int -// CHECK-DAG: error: verification failed: is_max [{{.*}}::postcondition@ +// CHECK-DAG: error: verification failed: is_max [postcondition] int quotient(int x, int y) cppverify::pre(y != 0 && !(x == -2147483647 - 1 && y == -1)) @@ -65,7 +66,7 @@ void divides_by_zero(int x, int y) cppverify::post(x / y == x / y) { } -// CHECK-DAG: error: verification failed: divides_by_zero [{{.*}}::division-by-zero@ +// CHECK-DAG: error: verification failed: divides_by_zero [division-by-zero] int even(int x) cppverify::pre(x >= 0 && x < 1000) @@ -89,7 +90,7 @@ int cast_overflows(int x) { return 0; } -// CHECK-DAG: error: verification failed: cast_overflows [{{.*}}::overflow@ +// CHECK-DAG: error: verification failed: cast_overflows [overflow] constexpr int twice(int v) { return v + v; } From 67e66cbc9458be687b6e2f33abc9aff96ed0bb06 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:46 +0530 Subject: [PATCH 072/259] test: Expect failures as Clang diagnostics in contract_wellformedness.cpp. --- .../Verify/suite/contract_wellformedness.cpp | 66 ++++++++++--------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/clang/test/Verify/suite/contract_wellformedness.cpp b/clang/test/Verify/suite/contract_wellformedness.cpp index c631d0b0ea..59bd58da53 100644 --- a/clang/test/Verify/suite/contract_wellformedness.cpp +++ b/clang/test/Verify/suite/contract_wellformedness.cpp @@ -25,10 +25,11 @@ int ratio(int a, int b) { return 0; } -// CHECK: [[@LINE-4]]:20: error: verification failed: contract of ratio [{{.*}}::contract::division-by-zero@[[@LINE-4]]:20] (counterexample: b [ssa=b_0] [type=i32] = 0) -// CHECK-NEXT: Verified: ratio [backend=z3] -// BMC: error: verification failed: contract of ratio [{{.*}}::contract::division-by-zero@ -// NOUB: error: verification failed: contract of ratio [{{.*}}::contract::division-by-zero@ +// CHECK: [[@LINE-4]]:20: error: verification failed: contract of ratio [division-by-zero] +// CHECK: note: counterexample: b = 0 +// CHECK: Verified: ratio [backend=z3] +// BMC: error: verification failed: contract of ratio [division-by-zero] +// NOUB: error: verification failed: contract of ratio [division-by-zero] int ratio_ok(int a, int b) cppverify::pre(b != 0 && a / b == 0) @@ -43,8 +44,9 @@ int deref(const int *p) { return 0; } -// CHECK: [[@LINE-4]]:18: error: verification failed: contract of deref [{{.*}}::contract::dereference@[[@LINE-4]]:18] (counterexample: p [ssa=p_0] [type=pointer] = 0) -// NOUB: error: verification failed: contract of deref [{{.*}}::contract::dereference@ +// CHECK: [[@LINE-4]]:18: error: verification failed: contract of deref [dereference] +// CHECK: note: counterexample: p = 0 +// NOUB: error: verification failed: contract of deref [dereference] int deref_ok(const int *p) cppverify::pre(p != nullptr && *p > 0) @@ -59,8 +61,8 @@ int at(const int *p, int i) { return 0; } -// CHECK: [[@LINE-4]]:33: error: verification failed: contract of at [{{.*}}::contract::bounds@[[@LINE-4]]:33] -// NOUB: error: verification failed: contract of at [{{.*}}::contract::dereference@ +// CHECK: [[@LINE-4]]:33: error: verification failed: contract of at [bounds] +// NOUB: error: verification failed: contract of at [dereference] int at_ok(const int *p, int i) cppverify::pre(valid(p, 8) && 0 <= i && i < 8 && p[i] == 3) @@ -78,7 +80,7 @@ int second(const int *p) { return 0; } -// CHECK: [[@LINE-4]]:34: error: verification failed: contract of second [{{.*}}::contract::bounds@[[@LINE-4]]:34] +// CHECK: [[@LINE-4]]:34: error: verification failed: contract of second [bounds] // NOUB-NOT: contract of second int slot(const Ring *r, int i) @@ -86,8 +88,8 @@ int slot(const Ring *r, int i) { return 0; } -// CHECK: [[@LINE-4]]:31: error: verification failed: contract of slot [{{.*}}::contract::bounds@[[@LINE-4]]:31] -// NOUB: error: verification failed: contract of slot [{{.*}}::contract::bounds@ +// CHECK: [[@LINE-4]]:31: error: verification failed: contract of slot [bounds] +// NOUB: error: verification failed: contract of slot [bounds] constexpr bool positive(int v) { return v > 0; } @@ -96,7 +98,8 @@ int next_positive(int x) { return 0; } -// CHECK: [[@LINE-4]]:29: error: verification failed: contract of next_positive [{{.*}}::contract::overflow@[[@LINE-4]]:29] (counterexample: x [ssa=x_0] [type=i32] = 2147483647) +// CHECK: [[@LINE-4]]:29: error: verification failed: contract of next_positive [overflow] +// CHECK: note: counterexample: x = 2147483647 constexpr int share(int v) { return 100 / v; } @@ -106,7 +109,8 @@ int shared(int x) { return 0; } -// CHECK: [[@LINE-4]]:18: error: verification failed: contract of shared [{{.*}}::contract::division-by-zero@[[@LINE-4]]:18] (counterexample: x [ssa=x_0] [type=i32] = 0) +// CHECK: [[@LINE-4]]:18: error: verification failed: contract of shared [division-by-zero] +// CHECK: note: counterexample: x = 0 // Order: a clause, an operand of && or ||, a branch of ?:, and a quantifier's // body are evaluated where what comes before them holds. @@ -125,7 +129,8 @@ int reversed(int a, int b) { return 0; } -// CHECK: [[@LINE-5]]:20: error: verification failed: contract of reversed [{{.*}}::contract::division-by-zero@[[@LINE-5]]:20] (counterexample: b [ssa=b_0] [type=i32] = 0) +// CHECK: [[@LINE-5]]:20: error: verification failed: contract of reversed [division-by-zero] +// CHECK: note: counterexample: b = 0 int either(int a, int b) cppverify::pre(b == 0 || a / b > 0) @@ -154,7 +159,7 @@ int one_more(const int *a, int n) { return 0; } -// CHECK: [[@LINE-4]]:18: error: verification failed: contract of one_more [{{.*}}::contract::bounds@[[@LINE-4]]:18] +// CHECK: [[@LINE-4]]:18: error: verification failed: contract of one_more [bounds] int sign(int x) cppverify::behavior(positive, x > 0) @@ -175,8 +180,8 @@ int read_ahead(const int *p, int i) { return p[i]; } -// CHECK: [[@LINE-4]]:37: error: verification failed: read_ahead [{{.*}}::bounds@[[@LINE-4]]:37] -// BMC: error: verification failed: read_ahead [{{.*}}::bounds@ +// CHECK: [[@LINE-4]]:37: error: verification failed: read_ahead [bounds] +// BMC: error: verification failed: read_ahead [bounds] int one(int x) cppverify::post(cppverify::result != 0) @@ -192,7 +197,7 @@ int zero(int x) { return 0; } -// CHECK: [[@LINE-5]]:37: error: verification failed: zero [{{.*}}::postcondition@[[@LINE-5]]:37] +// CHECK: [[@LINE-5]]:37: error: verification failed: zero [postcondition] // CHECK-NOT: division-by-zero // A loop invariant and an assertion read memory as the body does. @@ -209,7 +214,7 @@ int walk(const int *p, int n) } return 0; } -// CHECK: [[@LINE-7]]:43: error: verification failed: walk [{{.*}}::bounds@[[@LINE-7]]:43 +// CHECK: [[@LINE-7]]:43: error: verification failed: walk [bounds] int last(const int *p, int n) cppverify::pre(valid(p, n) && n >= 1 && n <= 100) @@ -218,8 +223,8 @@ int last(const int *p, int n) cppverify::check(p[n] >= 0); return 0; } -// CHECK: [[@LINE-3]]:3: error: verification failed: last [{{.*}}::bounds@[[@LINE-3]]:3] -// BMC: error: verification failed: last [{{.*}}::bounds@ +// CHECK: [[@LINE-3]]:3: error: verification failed: last [bounds] +// BMC: error: verification failed: last [bounds] int ghost_last(const int *p, int n) cppverify::pre(valid(p, n) && n >= 1 && n <= 100) @@ -227,7 +232,7 @@ int ghost_last(const int *p, int n) cppverify::ghost { cppverify::check(p[n] >= 0 || p[n] < 0); } return 0; } -// CHECK: [[@LINE-3]]:22: error: verification failed: ghost_last [{{.*}}::bounds@[[@LINE-3]]:22] +// CHECK: [[@LINE-3]]:22: error: verification failed: ghost_last [bounds] // The postcondition before it holds, and the body's own state places the // result: *result lies in p. @@ -274,7 +279,7 @@ int next_object(const int *p, const int *q) p = p + 1; return q[0]; } -// CHECK: [[@LINE-5]]:37: error: verification failed: next_object [{{.*}}::bounds@[[@LINE-5]]:37] +// CHECK: [[@LINE-5]]:37: error: verification failed: next_object [bounds] int prev_object(const int *p, const int *q) cppverify::pre(valid(p, 2) && valid(q, 2) && q == p + 2 && p[2] == 0) @@ -282,13 +287,14 @@ int prev_object(const int *p, const int *q) p = p + 1; return 0; } -// CHECK: [[@LINE-5]]:55: error: verification failed: contract of prev_object [{{.*}}::contract::bounds@[[@LINE-5]]:55] +// CHECK: [[@LINE-5]]:55: error: verification failed: contract of prev_object [bounds] // A trusted contract holds in every state its frame allows, with any result. [[cppverify::trusted]] int inverse(int x) cppverify::post(10 / cppverify::result > 0); // CHECK: Trusted: inverse (contract assumed, not verified) -// CHECK-NEXT: [[@LINE-2]]:22: error: verification failed: contract of inverse [{{.*}}::contract::division-by-zero@[[@LINE-2]]:22] (counterexample: result [ssa=__result_1] [type=i32] = 0) +// CHECK-NEXT: [[@LINE-2]]:22: error: verification failed: contract of inverse [division-by-zero] +// CHECK: note: counterexample: result = 0 [[cppverify::trusted]] int nonzero(int x) cppverify::post(cppverify::result != 0) @@ -305,7 +311,7 @@ int prev_object(const int *p, const int *q) [[cppverify::trusted]] int *find_any(int *p, int x) cppverify::pre(valid(p, 4)) cppverify::post(*cppverify::result == x); -// CHECK: [[@LINE-1]]:19: error: verification failed: contract of find_any [{{.*}}::contract::dereference@[[@LINE-1]]:19] +// CHECK: [[@LINE-1]]:19: error: verification failed: contract of find_any [dereference] // What the frame does not name keeps its value: *q stays nonzero. [[cppverify::trusted]] void scale(int *p, const int *q) @@ -319,14 +325,14 @@ int prev_object(const int *p, const int *q) cppverify::pre(p != nullptr && q != nullptr && *q != 0) cppverify::modifies(*p, *q) cppverify::post(*p == cppverify::old(*p) + 10 / *q); -// CHECK: [[@LINE-1]]:49: error: verification failed: contract of scale_both [{{.*}}::contract::division-by-zero@[[@LINE-1]]:49] +// CHECK: [[@LINE-1]]:49: error: verification failed: contract of scale_both [division-by-zero] // A contract without a definition is checked too. int past(const int *p, int n) cppverify::pre(valid(p, n) && n >= 1) cppverify::post(cppverify::result == p[n]); // CHECK: warning: past has a contract but no definition -// CHECK-NEXT: [[@LINE-2]]:40: error: verification failed: contract of past [{{.*}}::contract::bounds@[[@LINE-2]]:40] +// CHECK: [[@LINE-2]]:40: error: verification failed: contract of past [bounds] // A trusted contract whose extent marker cannot be read establishes nothing. [[cppverify::trusted]] int either_end(const int *p, int n) @@ -373,8 +379,8 @@ cppverify::proof void lemma(const int *a, int n) cppverify::pre(valid(a, n) && n >= 1 && a[n] == 0) { } -// CHECK: [[@LINE-3]]:43: error: verification failed: contract of lemma [{{.*}}::contract::bounds@[[@LINE-3]]:43] -// CHECK-NEXT: Verified: lemma [backend=z3] +// CHECK: [[@LINE-3]]:43: error: verification failed: contract of lemma [bounds] +// CHECK: Verified: lemma [backend=z3] // A spec is total: division by zero is zero there, and it has no // precondition to check. From 88355dafa872a91879532e781b3c24e16a4f55b8 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:47 +0530 Subject: [PATCH 073/259] test: Expect failures as Clang diagnostics in contracts_across_files.test. --- clang/test/Verify/suite/contracts_across_files.test | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/contracts_across_files.test b/clang/test/Verify/suite/contracts_across_files.test index 05e410f9e0..13ea35a459 100644 --- a/clang/test/Verify/suite/contracts_across_files.test +++ b/clang/test/Verify/suite/contracts_across_files.test @@ -30,7 +30,8 @@ RIGHT-NEXT: Summary: 3 verified WRONG: Unresolved: scaled [backend=z3] [reason=callee.contract] (relies on the contract of clamp100, which its verification in {{.*}}mathx.cpp does not establish) WRONG-NEXT: Unresolved: twice_scaled [backend=z3] [reason=callee.contract] (relies on the contract of clamp100, which its verification in {{.*}}mathx.cpp does not establish) -WRONG-NEXT: mathx.h:2:42: error: verification failed: clamp100 [{{.*}}::postcondition@2:42] (counterexample: {{.*}}result [ssa=__result_1] [type=i32] = 101 +WRONG: mathx.h:2:42: error: verification failed: clamp100 [postcondition] +WRONG: note: counterexample: {{.*}}result = 101{{( ->|,|$)}} WRONG: Summary: 1 failed, 2 unresolved (callee.contract 2) The files are printed in the order they are given, settled together. @@ -43,7 +44,7 @@ JSON: "function":"clamp100","message":"verification failed: clamp100 A file alone is as before: the contract has no definition. ALONE: mathx.h:1:5: warning: clamp100 has a contract but no definition, so its callers are not verified; mark the declaration {{\[\[cppverify::trusted\]\]}} to assume the contract -ALONE-NEXT: Unresolved: scaled [backend=z3] [reason=callee.contract] (relies on the contract of clamp100 (no definition; mark it {{\[\[cppverify::trusted\]\]}} to assume it), which is not established) +ALONE: Unresolved: scaled [backend=z3] [reason=callee.contract] (relies on the contract of clamp100 (no definition; mark it {{\[\[cppverify::trusted\]\]}} to assume it), which is not established) ALONE-NEXT: Unresolved: twice_scaled [backend=z3] [reason=callee.contract] (relies on the contract of scaled, which is not established) A declaration that states another contract is not the definition's. From 73c4b8950d89f7005f0c52dfae8a12bebe64c754 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:47 +0530 Subject: [PATCH 074/259] test: Expect failures as Clang diagnostics in counterexample_confirmation.cpp. --- .../Verify/suite/counterexample_confirmation.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/clang/test/Verify/suite/counterexample_confirmation.cpp b/clang/test/Verify/suite/counterexample_confirmation.cpp index 7895f51356..adc5c930f3 100644 --- a/clang/test/Verify/suite/counterexample_confirmation.cpp +++ b/clang/test/Verify/suite/counterexample_confirmation.cpp @@ -31,7 +31,8 @@ cppverify::proof void small_power(int n) cppverify::post(pow2(n) < 1000) { } -// CHECK-DAG: error: verification failed: small_power {{.*}}(counterexample: n [ssa=n_0] [type=i32] = {{[0-9]+}}; confirmed by a proof at this input, since its check could not compute pow2({{[0-9]+}})) [backend=z3] [reason=counterexample] +// CHECK-DAG: error: verification failed: small_power [postcondition] (confirmed by a proof at this input, since its check could not compute pow2({{[0-9]+}})) [backend=z3] [reason=counterexample] +// CHECK-DAG: note: counterexample: n = {{[0-9]+}} cppverify::spec int fibo(int n) cppverify::decreases(n) @@ -57,7 +58,8 @@ cppverify::proof void fibo_small(int n) cppverify::post(fibo(n) < 5) { } -// CHECK-DAG: error: verification failed: fibo_small {{.*}}(counterexample: n [ssa=n_0] [type=i32] = 1000000000; confirmed by a proof at this input that uses the contract of fibo_at_least_5, since its check could not compute fibo(1000000000)) [backend=z3] [reason=counterexample] +// CHECK-DAG: error: verification failed: fibo_small [postcondition] (confirmed by a proof at this input that uses the contract of fibo_at_least_5, since its check could not compute fibo(1000000000)) [backend=z3] [reason=counterexample] +// CHECK-DAG: note: counterexample: n = 1000000000 // JSON-DAG: "confirmed_with":["fibo_at_least_5"] // The same with a lemma that does not hold: a confirmation uses only the @@ -124,7 +126,9 @@ cppverify::spec int capped(int n) { return fibo(n); } -// CHECK-DAG: error: spec post failed: capped [backend=z3] [reason=counterexample] (n [type=math-i32] = 1000000000; confirmed by a proof at this input that uses the contract of fibo_at_least_5, since its check could not compute fibo(1000000000)) +// CHECK-DAG: error: spec post failed: capped [backend=z3] [reason=counterexample] (confirmed by a proof at this input that uses the contract of fibo_at_least_5, since its check could not compute fibo(1000000000)) +// CHECK-DAG: note: counterexample: n = 1000000000 +// CHECK-DAG: note: counterexample: {{.*}}n = 1000000000{{( ->|,|$)}} // A lemma is used through what its verification proved: its postconditions // wherever every assumption its proof started from holds. Besides its own @@ -157,7 +161,8 @@ cppverify::proof void fib4_small(int n) { } // CHECK-DAG: Verified: fib4_at_least_5 -// CHECK-DAG: error: verification failed: fib4_small {{.*}}(counterexample: n [ssa=n_0] [type=i32] = 1000000000; confirmed by a proof at this input that uses the contract of fib4_at_least_5, since its check could not compute fib4(1000000000)) [backend=z3] [reason=counterexample] +// CHECK-DAG: error: verification failed: fib4_small [postcondition] (confirmed by a proof at this input that uses the contract of fib4_at_least_5, since its check could not compute fib4(1000000000)) [backend=z3] [reason=counterexample] +// CHECK-DAG: note: counterexample: n = 1000000000 // The same through mutable pointers, which must be distinct objects (or // null), and through a record whose type invariant the proof assumes. From 6f6040548845e0206f415e72c7fa32f312ba69cc Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:47 +0530 Subject: [PATCH 075/259] test: Expect failures as Clang diagnostics in demoted_vacuity.cpp. --- clang/test/Verify/suite/demoted_vacuity.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/clang/test/Verify/suite/demoted_vacuity.cpp b/clang/test/Verify/suite/demoted_vacuity.cpp index 223c45fa56..c760bfb462 100644 --- a/clang/test/Verify/suite/demoted_vacuity.cpp +++ b/clang/test/Verify/suite/demoted_vacuity.cpp @@ -21,7 +21,7 @@ int uses_loop(int x) cppverify::check(loop(x) > 0 || loop(x) <= 0); return 1; } -// CHECK-NEXT: Unresolved: uses_loop [backend=z3] [reason=spec.termination] (relies on the definition of loop, whose termination is not established) +// CHECK: Unresolved: uses_loop [backend=z3] [reason=spec.termination] (relies on the definition of loop, whose termination is not established) // The precondition holds for every x. int loop_in_precondition(int x) @@ -45,7 +45,7 @@ int uses_contradictory(int x) int r = contradictory(x); return r; } -// CHECK-NEXT: Unresolved: uses_contradictory [backend=z3] [reason=callee.contract] (relies on the contract of contradictory, which is not established) +// CHECK: Unresolved: uses_contradictory [backend=z3] [reason=callee.contract] (relies on the contract of contradictory, which is not established) // A contract that fails but does not contradict itself. int wrong_seven(int x) @@ -57,7 +57,7 @@ int wrong_seven(int x) [[cppverify::trusted]] void claims_nonnegative(int x) cppverify::post(x >= 0); -// CHECK-NEXT: Trusted: claims_nonnegative +// CHECK: Trusted: claims_nonnegative int contradicted(int x) cppverify::post(cppverify::result == 7) @@ -84,7 +84,7 @@ int never_applies(int x) { return wrong_seven(x); } -// CHECK-NEXT: Unresolved: never_applies [backend=z3] [reason=callee.contract] (relies on the contract of wrong_seven, which is not established) +// CHECK: Unresolved: never_applies [backend=z3] [reason=callee.contract] (relies on the contract of wrong_seven, which is not established) // CHECK-NEXT: warning: never_applies: behavior impossible never applies // A proof that stands keeps its finding. @@ -94,9 +94,9 @@ int unsatisfiable(int x) { return 0; } -// CHECK-NEXT: Verified: unsatisfiable [backend=z3] [vacuous] +// CHECK: Verified: unsatisfiable [backend=z3] [vacuous] // CHECK-NEXT: warning: unsatisfiable: the precondition is unsatisfiable, so every claim about it holds vacuously -// CHECK-NEXT: Summary: {{.*}} +// CHECK: Summary: {{.*}} // CHECK-NOT: {{.}} // JSON: "function":"uses_loop" From ed5a84edabfc4a735b8d8b4d87886c50b65677a0 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:48 +0530 Subject: [PATCH 076/259] test: Expect failures as Clang diagnostics in dynamic_storage_fail.cpp. --- clang/test/Verify/suite/dynamic_storage_fail.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/dynamic_storage_fail.cpp b/clang/test/Verify/suite/dynamic_storage_fail.cpp index fc6c1bf5e4..f15d51b2ac 100644 --- a/clang/test/Verify/suite/dynamic_storage_fail.cpp +++ b/clang/test/Verify/suite/dynamic_storage_fail.cpp @@ -439,7 +439,7 @@ int modular_discarded_pointer_forwarding() // VERIFY-DAG: Unresolved: modular_copied_pointer_return {{.*}}[reason=construct.unsupported] // VERIFY-DAG: Unresolved: modular_unsafe_forwarding {{.*}}[reason=construct.unsupported] // VERIFY-DAG: Unresolved: modular_discarded_pointer_forwarding {{.*}}[reason=construct.unsupported] -// VERIFY-DAG: error: verification failed: unsafe_forwarded_read [{{.*}}::bounds@107:37] +// VERIFY-DAG: :107:37: error: verification failed: unsafe_forwarded_read [bounds] // VERIFY-DAG: Verified: modular_forwarded_scalar // VERIFY-DAG: Verified: modular_forwarded_temporary // VERIFY-DAG: Verified: modular_forwarded_control From ced30983818c92f725334384408fc67e41f8bd2e Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:48 +0530 Subject: [PATCH 077/259] test: Expect failures as Clang diagnostics in enum_ranges.cpp. --- clang/test/Verify/suite/enum_ranges.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/clang/test/Verify/suite/enum_ranges.cpp b/clang/test/Verify/suite/enum_ranges.cpp index 7adc59e068..96acc5be64 100644 --- a/clang/test/Verify/suite/enum_ranges.cpp +++ b/clang/test/Verify/suite/enum_ranges.cpp @@ -71,21 +71,22 @@ bool fixed_type(Wide w) { return static_cast(w) < 2; } -// CHECK-DAG: error: verification failed: fixed_type [{{.*}}::postcondition@{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: fixed_type [postcondition]{{.*}}[reason=counterexample] Color convert(int i) cppverify::pre(0 <= i && i <= 4) { return static_cast(i); } -// CHECK-DAG: error: verification failed: convert [{{.*}}::overflow@{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: convert [overflow]{{.*}}[reason=counterexample] cppverify::spec bool small(Color c) cppverify::post(cppverify::result) { return c < 4; } -// CHECK-DAG: error: spec post failed: small [backend=z3] [reason=counterexample] (c [type=math-i32] = 4) +// CHECK-DAG: error: spec post failed: small [backend=z3] [reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}c = 4{{( ->|,|$)}} // The same check run as a proof function by its block. cppverify::spec bool small_by(Color c) From 2fb702799268e6374093b8a67e79d4fa4312b0e1 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:49 +0530 Subject: [PATCH 078/259] test: Expect failures as Clang diagnostics in extent_separation.cpp. --- clang/test/Verify/suite/extent_separation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/extent_separation.cpp b/clang/test/Verify/suite/extent_separation.cpp index 4219158d5d..436473e894 100644 --- a/clang/test/Verify/suite/extent_separation.cpp +++ b/clang/test/Verify/suite/extent_separation.cpp @@ -65,7 +65,7 @@ void wrong_copy(const int *a, int *out, int n) i = i + 1; } } -// DECIDED-DAG: verification failed: wrong_copy [{{.*}}::invariant-preserved@ +// DECIDED-DAG: verification failed: wrong_copy [invariant-preserved] // BV-DAG: {{verification failed|Unresolved}}: wrong_copy // The separation must not make the preconditions contradictory. @@ -113,7 +113,7 @@ int overlapping_caller(int *buffer) { return inspect(buffer + 2, buffer, 4); } -// CHECK-DAG: verification failed: overlapping_caller [{{.*}}::aliasing@ +// CHECK-DAG: verification failed: overlapping_caller [aliasing] int empty_caller(int *buffer) cppverify::pre(valid(buffer, 8)) From 0b83f216413a2edb94430899fba6a4d6b9143ba8 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:49 +0530 Subject: [PATCH 079/259] test: Expect failures as Clang diagnostics in forall_introduction.cpp. --- clang/test/Verify/suite/forall_introduction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/forall_introduction.cpp b/clang/test/Verify/suite/forall_introduction.cpp index d1ee763593..e3321af9fd 100644 --- a/clang/test/Verify/suite/forall_introduction.cpp +++ b/clang/test/Verify/suite/forall_introduction.cpp @@ -40,7 +40,7 @@ cppverify::proof void strictly_below_last(const int *a, int n) pair_ordered(a, n, k, n - 1); } } -// CHECK-DAG: error: verification failed: strictly_below_last [{{.*}}::assertion@[[@LINE-4]]:3] (counterexample: {{.*}}) [backend=z3] [reason=counterexample] +// CHECK-DAG: :[[@LINE-4]]:3: error: verification failed: strictly_below_last [assertion] [backend=z3] [reason=counterexample] // Without bounds the variable ranges over every integer. cppverify::proof void squares(int m) From e0f25b3f85d1bff2669dc6aca16830af8358a16a Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:50 +0530 Subject: [PATCH 080/259] test: Expect failures as Clang diagnostics in frame_call_objects.cpp. --- clang/test/Verify/suite/frame_call_objects.cpp | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/clang/test/Verify/suite/frame_call_objects.cpp b/clang/test/Verify/suite/frame_call_objects.cpp index 8de22ab475..1f77462e29 100644 --- a/clang/test/Verify/suite/frame_call_objects.cpp +++ b/clang/test/Verify/suite/frame_call_objects.cpp @@ -105,7 +105,7 @@ void neighbor_cell(int *a) { set(a + 3, 5); } -// CHECK-DAG: error: verification failed: neighbor_cell [{{.*}}::frame@[[@LINE-2]]:3] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: neighbor_cell [frame] // A copy into another parameter's object, outside the caller's region. void other_object(int *a, int *b) @@ -115,7 +115,7 @@ void other_object(int *a, int *b) int *q = b + 1; set(q, 5); } -// CHECK-DAG: error: verification failed: other_object [{{.*}}::frame@[[@LINE-2]]:3] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: other_object [frame] // The copy starts inside a's object only if b lay below it. void other_object_above(int *a, int *b) @@ -125,7 +125,7 @@ void other_object_above(int *a, int *b) int *q = b + 1; set(q, 5); } -// CHECK-DAG: error: verification failed: other_object_above [{{.*}}::frame@[[@LINE-2]]:3] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: other_object_above [frame] // A callee may name more cells than its extent: these run past a's object. void wide(int *p) @@ -143,7 +143,7 @@ void wide_past(int *a) int *q = a + 3; wide(q); } -// CHECK-DAG: error: verification failed: wide_past [{{.*}}::frame@[[@LINE-2]]:3] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: wide_past [frame] // When c is false the cell is in b, which the caller may not write. void chosen_outside(int *a, int *b, bool c) @@ -153,7 +153,8 @@ void chosen_outside(int *a, int *b, bool c) int *q = c ? a + 1 : b + 3; set(q, 5); } -// CHECK-DAG: error: verification failed: chosen_outside [{{.*}}::frame@[[@LINE-2]]:3] (counterexample: {{.*}}c [ssa=c_0] [type=bool] = false, +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: chosen_outside [frame] +// CHECK-DAG: note: counterexample: {{.*}}c = false{{( ->|,|$)}} // The cell before the object, where its end would still be inside. [[cppverify::trusted]] int *before(const int *a, int n) @@ -168,7 +169,7 @@ void before_object(int *a) int *q = before(a, 4); set(q, 5); } -// CHECK-DAG: error: verification failed: before_object [{{.*}}::frame@[[@LINE-2]]:3] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: before_object [frame] // The range a[3 : 2] runs past the cell a[3] the caller may write. void range_past_cell(int *a) @@ -178,4 +179,4 @@ void range_past_cell(int *a) int *q = a + 3; zero2(q, 2); } -// CHECK-DAG: error: verification failed: range_past_cell [{{.*}}::frame@[[@LINE-2]]:3] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: range_past_cell [frame] From c392eb99dbc57f93a5cd7afce3880ccbbbf7ece1 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:50 +0530 Subject: [PATCH 081/259] test: Expect failures as Clang diagnostics in frontend_gaps.cpp. --- clang/test/Verify/suite/frontend_gaps.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/frontend_gaps.cpp b/clang/test/Verify/suite/frontend_gaps.cpp index bb1c9036fb..d576fc598e 100644 --- a/clang/test/Verify/suite/frontend_gaps.cpp +++ b/clang/test/Verify/suite/frontend_gaps.cpp @@ -26,7 +26,8 @@ bool is_digit_wrong(char c) { return c >= '0' && c <= '9'; } -// CHECK-DAG: error: verification failed: is_digit_wrong [{{.*}}c [ssa=c_0] [type=i8] = 57{{[,;]}}{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: is_digit_wrong {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}c = 57{{( ->|,|$)}} int digit_value(char c) cv::pre('0' <= c && c <= '9') From c3d21378009347d47589ea93e2963b36ecdbc5a2 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:51 +0530 Subject: [PATCH 082/259] test: Expect failures as Clang diagnostics in function_filter.cpp. --- clang/test/Verify/suite/function_filter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/function_filter.cpp b/clang/test/Verify/suite/function_filter.cpp index 91da544d7e..940fc41a58 100644 --- a/clang/test/Verify/suite/function_filter.cpp +++ b/clang/test/Verify/suite/function_filter.cpp @@ -142,7 +142,7 @@ cv::spec bool climbs(int a, int b) // STEP: Verified: inductive predicate: climbs // STEP-NEXT: Unresolved: spec post: climbs [reason=spec.post] (relies on the postcondition of climbs.step, which is not established) // STEP-NEXT: function_filter.cpp:92:24: error: spec post by induction failed: climbs -// STEP-NEXT: Summary: 1 verified, 1 failed, 1 unresolved (spec.post 1) +// STEP: Summary: 1 verified, 1 failed, 1 unresolved (spec.post 1) // NONE: error: no function matches --function=nothing From eaa3c24fd4c62d450a64cea5a4f2ef15d500b600 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:51 +0530 Subject: [PATCH 083/259] test: Expect failures as Clang diagnostics in function_templates.cpp. --- clang/test/Verify/suite/function_templates.cpp | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/clang/test/Verify/suite/function_templates.cpp b/clang/test/Verify/suite/function_templates.cpp index 5c7b797aea..018a905116 100644 --- a/clang/test/Verify/suite/function_templates.cpp +++ b/clang/test/Verify/suite/function_templates.cpp @@ -60,11 +60,12 @@ signed char twice_char(signed char x) } // CHECK-DAG: Verified: twice [backend=z3] // CHECK-DAG: Verified: twice_int [backend=z3] -// CHECK-DAG: error: verification failed: twice [{{.*}}::postcondition@[[@LINE-20]]:{{.*}} x [ssa=x_0] [type=i8] = {{6[4-9]|[7-9][0-9]|100}} +// CHECK-DAG: :[[@LINE-20]]:{{[0-9]+}}: error: verification failed: twice [postcondition] +// CHECK-DAG: note: counterexample: {{.*}}x = {{6[4-9]|[7-9][0-9]|100}}{{( ->|,|$)}} // CHECK-DAG: Unresolved: twice_char [backend=z3] [reason=callee.contract] (relies on the contract of twice, which is not established) // NOTE: error: verification failed: twice -// NOTE-NEXT: function_templates.cpp:[[@LINE-8]]:19: note: in instantiation of function template specialization 'twice' requested here -// JSON: "function":"twice","instantiated_at":{"column":19,"end_column":19,"end_line":[[@LINE-9]],"file":"{{.*}}function_templates.cpp","line":[[@LINE-9]]} +// NOTE: function_templates.cpp:[[@LINE-9]]:19: note: in instantiation of function template specialization 'twice' requested here +// JSON: "function":"twice","instantiated_at":{"column":19,"end_column":19,"end_line":[[@LINE-10]],"file":"{{.*}}function_templates.cpp","line":[[@LINE-10]]} // A recursive template calls its own specialization. template @@ -143,10 +144,10 @@ short total_short(const short *p, int n) } // CHECK-DAG: Verified: total [backend=z3] // CHECK-DAG: Verified: total_int [backend=z3] -// CHECK-DAG: error: verification failed: total [{{.*}}::invariant-preserved@ +// CHECK-DAG: error: verification failed: total [invariant-preserved] // CHECK-DAG: Unresolved: total_short [backend=z3] [reason=callee.contract] // NOTE: error: verification failed: total -// NOTE-NEXT: function_templates.cpp:[[@LINE-8]]:13: note: in instantiation of function template specialization 'total' requested here +// NOTE: function_templates.cpp:[[@LINE-8]]:13: note: in instantiation of function template specialization 'total' requested here // Ghost code of a template's types, a ghost variable assigned in a ghost // block. @@ -415,4 +416,5 @@ int product_of(Ns... ns) } int products() { return product_of(2, 3); } -// CHECK-DAG: error: verification failed: product_of [{{.*}}::postcondition@[[@LINE-6]]:{{.*}} ns...[0] [ssa=ns...[0]_0] [type=i32] = {{.*}} ns...[1] [ssa=ns...[1]_0] [type=i32] = +// CHECK-DAG: :[[@LINE-6]]:{{[0-9]+}}: error: verification failed: product_of [postcondition] +// CHECK-DAG: note: counterexample: ns...[0] = {{[0-9]+}}, ns...[1] = {{[0-9]+}}, result = {{[0-9]+}} From 71014a25043d9ee50b2afb6582ec5aa36f2742dd Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:52 +0530 Subject: [PATCH 084/259] test: Expect failures as Clang diagnostics in ghost_locals.cpp. --- clang/test/Verify/suite/ghost_locals.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/ghost_locals.cpp b/clang/test/Verify/suite/ghost_locals.cpp index f197d55a17..d295f139d6 100644 --- a/clang/test/Verify/suite/ghost_locals.cpp +++ b/clang/test/Verify/suite/ghost_locals.cpp @@ -44,4 +44,4 @@ int remembers_wrong(int x) cppverify::check(x == before); return x; } -// CHECK-DAG: error: verification failed: remembers_wrong [{{.*}}::assertion@ +// CHECK-DAG: error: verification failed: remembers_wrong [assertion] From d0d1825e38b93f2f644c485c0e217ed79568255d Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:52 +0530 Subject: [PATCH 085/259] test: Expect failures as Clang diagnostics in ghost_math_values.cpp. --- clang/test/Verify/suite/ghost_math_values.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/test/Verify/suite/ghost_math_values.cpp b/clang/test/Verify/suite/ghost_math_values.cpp index a0094a2217..002b294388 100644 --- a/clang/test/Verify/suite/ghost_math_values.cpp +++ b/clang/test/Verify/suite/ghost_math_values.cpp @@ -26,7 +26,7 @@ cppverify::proof void stores_element(seq s) { int x = s[0]; } -// CHECK-DAG: error: verification failed: stores_element [{{.*}}::overflow@[[@LINE-2]]:3] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: stores_element [overflow] cppverify::proof void stores_bounded_element(seq s) cppverify::pre(s.len() > 0 && 0 <= s[0] && s[0] < 100) @@ -48,7 +48,7 @@ cppverify::proof void passes_length(seq s) { takes_int(s.len() + 2147483647); } -// CHECK-DAG: error: verification failed: passes_length [{{.*}}::overflow@[[@LINE-2]]:3] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: passes_length [overflow] cppverify::proof void passes_bounded_length(seq s) cppverify::pre(s.len() < 1000) @@ -77,4 +77,4 @@ void ghost_length_too_large(int n) int k = s.len() + 2147483647; } } -// CHECK-DAG: error: verification failed: ghost_length_too_large [{{.*}}::overflow@ +// CHECK-DAG: error: verification failed: ghost_length_too_large [overflow] From 06026d096ea4a999032b9b58c1e3084fd7f9980a Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:53 +0530 Subject: [PATCH 086/259] test: Expect failures as Clang diagnostics in globals.cpp. --- clang/test/Verify/suite/globals.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/test/Verify/suite/globals.cpp b/clang/test/Verify/suite/globals.cpp index 9bc95c3bb4..102d799894 100644 --- a/clang/test/Verify/suite/globals.cpp +++ b/clang/test/Verify/suite/globals.cpp @@ -39,7 +39,7 @@ void bump_unframed() { counter = counter + 1; } -// CHECK-DAG: error: verification failed: bump_unframed [{{.*}}::frame@ +// CHECK-DAG: error: verification failed: bump_unframed [frame] int twice() cppverify::pre(counter < 100) @@ -67,7 +67,7 @@ void frames_wrong(int *p) { bump(); } -// CHECK-DAG: error: verification failed: frames_wrong [{{.*}}::frame@ +// CHECK-DAG: error: verification failed: frames_wrong [frame] void forgets_old() cppverify::pre(counter < 1000) @@ -76,6 +76,6 @@ void forgets_old() { bump(); } -// CHECK-DAG: error: verification failed: forgets_old [{{.*}}::postcondition@ +// CHECK-DAG: error: verification failed: forgets_old [postcondition] // SPEC: error: reads_counter: a spec function cannot read the mutable global counter; pass its value as a parameter From d24ca4025f9069fca0b4a19077fe4588c43f6c49 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:53 +0530 Subject: [PATCH 087/259] test: Expect failures as Clang diagnostics in inductive_counterexamples.cpp. --- .../suite/inductive_counterexamples.cpp | 56 ++++++++++--------- 1 file changed, 29 insertions(+), 27 deletions(-) diff --git a/clang/test/Verify/suite/inductive_counterexamples.cpp b/clang/test/Verify/suite/inductive_counterexamples.cpp index 7ce2f26981..b052252f18 100644 --- a/clang/test/Verify/suite/inductive_counterexamples.cpp +++ b/clang/test/Verify/suite/inductive_counterexamples.cpp @@ -196,41 +196,43 @@ int count_up_proved(int n) return c; } -// CHECK: inductive_counterexamples.cpp:16:23: error: verification failed: count_up [{{.*}}::postcondition@16:23] {{.*}}trace: loop.entry@19:3 -> loop.exit@19:3 -// CHECK-NEXT: note: the counterexample's state at the loop at 19:3 is any state its invariants allow, not necessarily one an execution reaches +// CHECK: inductive_counterexamples.cpp:16:23: error: verification failed: count_up [postcondition] +// CHECK: inductive_counterexamples.cpp:19:3: note: enters the loop +// CHECK: inductive_counterexamples.cpp:19:3: note: leaves the loop +// CHECK: note: the counterexample's state at the loop at 19:3 is any state its invariants allow, not necessarily one an execution reaches // CHECK-NEXT: note: no execution fails this check: every loop ends within 5 iterations, and unrolling proves it there; the loops' invariants are too weak for an unbounded proof -// CHECK-NEXT: inductive_counterexamples.cpp:29:23: error: verification failed: sum_wrong [{{.*}}::postcondition@29:23] -// CHECK-NEXT: note: the counterexample's state at the loop at 32:3 is any state its invariants allow, not necessarily one an execution reaches -// CHECK-NEXT: note: an execution fails this check within 1 iteration of each loop (counterexample: {{.*}}n [ssa=n_0] [type=i32] = 1{{.*}}) -// CHECK-NEXT: inductive_counterexamples.cpp:43:23: error: verification failed: far_wrong [{{.*}}::postcondition@43:23] -// CHECK-NEXT: note: the counterexample's state at the loop at 46:3 is any state its invariants allow, not necessarily one an execution reaches +// CHECK-NEXT: inductive_counterexamples.cpp:29:23: error: verification failed: sum_wrong [postcondition] +// CHECK: note: the counterexample's state at the loop at 32:3 is any state its invariants allow, not necessarily one an execution reaches +// CHECK-NEXT: note: an execution fails this check within 1 iteration of each loop (counterexample: {{.*}}n = 1{{.*}}) +// CHECK-NEXT: inductive_counterexamples.cpp:43:23: error: verification failed: far_wrong [postcondition] +// CHECK: note: the counterexample's state at the loop at 46:3 is any state its invariants allow, not necessarily one an execution reaches // CHECK-NEXT: note: no execution fails this check within 10 iterations of each loop -// CHECK-NEXT: inductive_counterexamples.cpp:57:23: error: verification failed: no_loop [{{.*}}::postcondition@57:23] -// CHECK-NEXT: inductive_counterexamples.cpp:64:23: error: verification failed: unmeasured [{{.*}}::postcondition@64:23] -// CHECK-NEXT: note: the loop at 67:3 has no cppverify::decreases: a proof would be Unresolved (decreases.missing) until it has one +// CHECK-NEXT: inductive_counterexamples.cpp:57:23: error: verification failed: no_loop [postcondition] +// CHECK: inductive_counterexamples.cpp:64:23: error: verification failed: unmeasured [postcondition] +// CHECK: note: the loop at 67:3 has no cppverify::decreases: a proof would be Unresolved (decreases.missing) until it has one // CHECK-NEXT: note: the counterexample's state at the loop at 67:3 is any state its invariants allow, not necessarily one an execution reaches -// CHECK-NEXT: note: an execution fails this check with no iteration of any loop (counterexample: {{.*}}n [ssa=n_0] [type=i32] = 0{{.*}}) -// CHECK-NEXT: inductive_counterexamples.cpp:87:7: error: verification failed: divides [{{.*}}::division-by-zero@87:7] -// CHECK-NEXT: note: the counterexample's state at the loop at 83:3 is any state its invariants allow, not necessarily one an execution reaches -// CHECK-NEXT: note: an execution fails this check within 4 iterations of each loop (counterexample: {{.*}}c [ssa=c_4] [type=i32] = 3{{.*}}) -// CHECK-NEXT: inductive_counterexamples.cpp:100:21: error: verification failed: grows [{{.*}}::invariant-preserved@100:21] -// CHECK-NEXT: note: the counterexample's state at the loop at 99:3 is any state its invariants allow, not necessarily one an execution reaches -// CHECK-NEXT: inductive_counterexamples.cpp:119:5: error: verification failed: two_checks [{{.*}}::assertion@119:5] -// CHECK-NEXT: note: the counterexample's state at the loop at 115:3 is any state its invariants allow, not necessarily one an execution reaches -// CHECK-NEXT: note: an execution fails this check within 5 iterations of each loop (counterexample: {{.*}}n [ssa=n_0] [type=i32] = 5{{.*}}) -// CHECK-NEXT: inductive_counterexamples.cpp:140:7: error: verification failed: two_kinds [{{.*}}::overflow@140:7] -// CHECK-NEXT: note: the counterexample's state at the loop at 136:3 is any state its invariants allow, not necessarily one an execution reaches +// CHECK-NEXT: note: an execution fails this check with no iteration of any loop (counterexample: {{.*}}n = 0{{.*}}) +// CHECK-NEXT: inductive_counterexamples.cpp:87:7: error: verification failed: divides [division-by-zero] +// CHECK: note: the counterexample's state at the loop at 83:3 is any state its invariants allow, not necessarily one an execution reaches +// CHECK-NEXT: note: an execution fails this check within 4 iterations of each loop (counterexample: {{.*}}c = 0 -> 1 -> 2 -> 3{{.*}}) +// CHECK-NEXT: inductive_counterexamples.cpp:100:21: error: verification failed: grows [invariant-preserved] +// CHECK: note: the counterexample's state at the loop at 99:3 is any state its invariants allow, not necessarily one an execution reaches +// CHECK-NEXT: inductive_counterexamples.cpp:119:5: error: verification failed: two_checks [assertion] +// CHECK: note: the counterexample's state at the loop at 115:3 is any state its invariants allow, not necessarily one an execution reaches +// CHECK-NEXT: note: an execution fails this check within 5 iterations of each loop (counterexample: {{.*}}n = 5{{.*}}) +// CHECK-NEXT: inductive_counterexamples.cpp:140:7: error: verification failed: two_kinds [overflow] +// CHECK: note: the counterexample's state at the loop at 136:3 is any state its invariants allow, not necessarily one an execution reaches // CHECK-NEXT: note: no execution fails this check without failing an earlier one first (the division-by-zero check at 140:7 fails): those that pass the checks before it end every loop within 2 iterations, and unrolling proves it there -// CHECK-NEXT: inductive_counterexamples.cpp:160:7: error: verification failed: past_failure [{{.*}}::division-by-zero@160:7] -// CHECK-NEXT: note: the counterexample's state at the loop at 156:3 is any state its invariants allow, not necessarily one an execution reaches -// CHECK-NEXT: note: an execution fails this check within 4 iterations of each loop (counterexample: {{.*}}k [ssa=k_0] [type=i32] = 3, m [ssa=m_0] [type=i32] = 100{{.*}}) -// CHECK-NEXT: inductive_counterexamples.cpp:170:23: error: verification failed: skipped [{{.*}}::postcondition@170:23] -// CHECK-NEXT: Verified: count_up_proved [backend=z3] +// CHECK-NEXT: inductive_counterexamples.cpp:160:7: error: verification failed: past_failure [division-by-zero] +// CHECK: note: the counterexample's state at the loop at 156:3 is any state its invariants allow, not necessarily one an execution reaches +// CHECK-NEXT: note: an execution fails this check within 4 iterations of each loop (counterexample: {{.*}}k = 3, m = 100{{.*}}) +// CHECK-NEXT: inductive_counterexamples.cpp:170:23: error: verification failed: skipped [postcondition] +// CHECK: Verified: count_up_proved [backend=z3] // CHECK-NEXT: Summary: 1 verified, 11 failed // Without unrolling, a failure still says where its state comes from. // NONE: error: verification failed: count_up -// NONE-NEXT: note: the counterexample's state at the loop at 19:3 is any state its invariants allow, not necessarily one an execution reaches +// NONE: note: the counterexample's state at the loop at 19:3 is any state its invariants allow, not necessarily one an execution reaches // NONE-NEXT: error: verification failed: sum_wrong // JSON: "function":"count_up",{{.*}}"notes":["the counterexample's state at the loop at 19:3 is any state its invariants allow, not necessarily one an execution reaches","no execution fails this check: every loop ends within 5 iterations{{.*}}"] From 88e03be4518d3fbd140bd232378296de9b2320b4 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:54 +0530 Subject: [PATCH 088/259] test: Expect failures as Clang diagnostics in inductive_lemmas.cpp. --- clang/test/Verify/suite/inductive_lemmas.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/inductive_lemmas.cpp b/clang/test/Verify/suite/inductive_lemmas.cpp index 50f20aad69..0a310414b3 100644 --- a/clang/test/Verify/suite/inductive_lemmas.cpp +++ b/clang/test/Verify/suite/inductive_lemmas.cpp @@ -54,7 +54,8 @@ cppverify::proof void four_after_three() cppverify::pre(od(3)) cppverify::post(e // A postcondition cannot assume itself: bad(0) holds, so !bad(0) fails. cppverify::spec bool bad(int n); cppverify::spec bool bad(int n) cppverify::inductive cppverify::post(!cppverify::result || !bad(n)) { return n == 0; } -// CHECK-DAG: error: spec post by induction failed: bad [backend=z3] [reason=counterexample] (derivation.height [type=math-i64] = {{[0-9]+}}, n [type=math-i32] = 0) +// CHECK-DAG: error: spec post by induction failed: bad [backend=z3] [reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}derivation.height = {{[0-9]+}}{{( ->|,|$)}}{{.*}}n = 0{{( ->|,|$)}} // CHECK-DAG: Unresolved: spec post: bad [reason=spec.post] cppverify::proof void contradiction() cppverify::post(false) { cppverify::check(bad(0)); } From e742613b9b7a670d1d24f93fdaa9f31a5389fc17 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:54 +0530 Subject: [PATCH 089/259] test: Expect failures as Clang diagnostics in inductive_predicates.cpp. --- clang/test/Verify/suite/inductive_predicates.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/inductive_predicates.cpp b/clang/test/Verify/suite/inductive_predicates.cpp index c4d838c4c1..6d8519754d 100644 --- a/clang/test/Verify/suite/inductive_predicates.cpp +++ b/clang/test/Verify/suite/inductive_predicates.cpp @@ -110,7 +110,8 @@ cppverify::spec bool odd(int n) { return n == 1 || odd(n - 2); } -// CHECK-DAG: error: spec post by induction failed: odd [backend=z3] [reason=counterexample] (derivation.height [type=math-i64] = {{[0-9]+}}, n [type=math-i32] = {{[0-9]+}}) +// CHECK-DAG: error: spec post by induction failed: odd [backend=z3] [reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}derivation.height = {{[0-9]+}}{{( ->|,|$)}}{{.*}}n = {{[0-9]+}}{{( ->|,|$)}} // CHECK-DAG: Unresolved: spec post: odd [reason=spec.post] (relies on the postcondition of odd.step, which is not established) // REJECT-DAG: error: negated: negated occurs in its body under negation; an inductive predicate occurs in its body only positively From 1929493c521d33868bc4ec78d58c66d28e9a0aee Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:55 +0530 Subject: [PATCH 090/259] test: Expect failures as Clang diagnostics in inductive_unfolding.cpp. --- clang/test/Verify/suite/inductive_unfolding.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/inductive_unfolding.cpp b/clang/test/Verify/suite/inductive_unfolding.cpp index eb747e45fe..71e4addae2 100644 --- a/clang/test/Verify/suite/inductive_unfolding.cpp +++ b/clang/test/Verify/suite/inductive_unfolding.cpp @@ -110,4 +110,5 @@ cppverify::spec bool path(int a, int b) { return a == b || cppverify::exists(c, edge(a, c) && path(c, b)); } -// CHECK-DAG: error: spec post by induction failed: path {{.*}}[reason=counterexample] ({{.*}}derivation.height [type=math-i64] = 1) +// CHECK-DAG: error: spec post by induction failed: path {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}derivation.height = 1{{( ->|,|$)}} From 415932f013603bf477606db4b315f2d59c2f12b5 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:55 +0530 Subject: [PATCH 091/259] test: Expect failures as Clang diagnostics in integer_encoding.cpp. --- clang/test/Verify/suite/integer_encoding.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/integer_encoding.cpp b/clang/test/Verify/suite/integer_encoding.cpp index 8162231413..41b8753252 100644 --- a/clang/test/Verify/suite/integer_encoding.cpp +++ b/clang/test/Verify/suite/integer_encoding.cpp @@ -84,6 +84,6 @@ int bad_negative_shift(int x) // DECIDED-DAG: Verified: shift_by_signed // UNDECIDED-DAG: {{Verified|Unresolved}}: shift_by_signed // VERIFY-DAG: error: verification failed: bad_wrap -// MODEL-DAG: x [ssa=x_0] [type=u32] = 4294967295; +// MODEL-DAG: note: counterexample: {{.*}}x = 4294967295{{( ->|,|$)}} // VERIFY-DAG: error: verification failed: bad_negative_shift -// MODEL-DAG: x [ssa=x_0] [type=i32] = 1; +// MODEL-DAG: note: counterexample: {{.*}}x = 1{{( ->|,|$)}} From 1fd10075c3c649ceb148fc8d005a644def0a6f4a Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:56 +0530 Subject: [PATCH 092/259] test: Expect failures as Clang diagnostics in lean_refutation.test. --- clang/test/Verify/suite/lean_refutation.test | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/clang/test/Verify/suite/lean_refutation.test b/clang/test/Verify/suite/lean_refutation.test index 9d98556ddd..d0b0fc82ef 100644 --- a/clang/test/Verify/suite/lean_refutation.test +++ b/clang/test/Verify/suite/lean_refutation.test @@ -65,12 +65,12 @@ # A contract, a bounded quantifier, a store to memory, and a spec Lean # defines; the choice is opaque in Lean. # CERTIFY: error: verification failed: add_one {{.*}}[reason=counterexample] (confirmed in Lean) -# CERTIFY-NEXT: error: verification failed: below_three {{.*}}[reason=counterexample] (confirmed in Lean) -# CERTIFY-NEXT: error: verification failed: zero_first {{.*}}[reason=counterexample] (confirmed in Lean) -# CERTIFY-NEXT: Verified: spec decreases: tri +# CERTIFY: error: verification failed: below_three {{.*}}[reason=counterexample] (confirmed in Lean) +# CERTIFY: error: verification failed: zero_first {{.*}}[reason=counterexample] (confirmed in Lean) +# CERTIFY: Verified: spec decreases: tri # CERTIFY-NEXT: error: verification failed: tri_three {{.*}}[reason=counterexample] (confirmed in Lean) -# CERTIFY-NEXT: error: verification failed: pick_one {{.*}}[reason=counterexample]{{$}} -# CERTIFY-NEXT: warning: the counterexample of pick_one is not confirmed in Lean: Lean cannot decide the goal at the counterexample +# CERTIFY: error: verification failed: pick_one {{.*}}[reason=counterexample]{{$}} +# CERTIFY: warning: the counterexample of pick_one is not confirmed in Lean: Lean cannot decide the goal at the counterexample # JSON: {"backend":"z3","function":"add_one","lean_refuted":true, # JSON: {"message":"the counterexample of pick_one is not confirmed in Lean: Lean cannot decide the goal at the counterexample","schema":"cppverify.diagnostic/1","severity":"warning","status":"warning"} From 26e766d7dbabf0ca17ff3097129534486107aed7 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:56 +0530 Subject: [PATCH 093/259] test: Expect failures as Clang diagnostics in llvm_uleb128_mutation.cpp. --- clang/test/Verify/suite/llvm_uleb128_mutation.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/llvm_uleb128_mutation.cpp b/clang/test/Verify/suite/llvm_uleb128_mutation.cpp index 31a728126c..ec178bec8d 100644 --- a/clang/test/Verify/suite/llvm_uleb128_mutation.cpp +++ b/clang/test/Verify/suite/llvm_uleb128_mutation.cpp @@ -51,6 +51,6 @@ unsigned encode_128_missing_continuation(uint8_t *buffer) // CHECK: Verified: encode_128 [backend=bmc, bound=1] // CHECK: error: verification failed: encode_128_missing_continuation -// CHECK-SAME: buffer -// CHECK-SAME: value=0 +// CHECK: note: counterexample: buffer = +// CHECK: note: stores 0 at address From b97f401bc5150ee31e00ef747429dc1a315abd86 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:57 +0530 Subject: [PATCH 094/259] test: Expect failures as Clang diagnostics in llvm_uleb128_shift_ub.cpp. --- clang/test/Verify/suite/llvm_uleb128_shift_ub.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/clang/test/Verify/suite/llvm_uleb128_shift_ub.cpp b/clang/test/Verify/suite/llvm_uleb128_shift_ub.cpp index 2526733def..657a136ffb 100644 --- a/clang/test/Verify/suite/llvm_uleb128_shift_ub.cpp +++ b/clang/test/Verify/suite/llvm_uleb128_shift_ub.cpp @@ -74,6 +74,5 @@ uint64_t decode_overlong_upstream(const uint8_t *buffer) } // namespace cppverify_uleb128_shift // CHECK: Verified: decode_overlong_repaired -// CHECK: error: verification failed: decode_overlong_upstream -// CHECK-SAME: shift -// CHECK-SAME: = 70 +// CHECK: error: verification failed: decode_overlong_upstream [shift] +// CHECK: note: counterexample: {{.*}}shift = {{.*}}70 From 736df0e1a3343801e9023fcfaf2bcf0df032d0fc Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:57 +0530 Subject: [PATCH 095/259] test: Expect failures as Clang diagnostics in local_names.cpp. --- clang/test/Verify/suite/local_names.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/local_names.cpp b/clang/test/Verify/suite/local_names.cpp index 8a62e0078d..b2eb7f8f01 100644 --- a/clang/test/Verify/suite/local_names.cpp +++ b/clang/test/Verify/suite/local_names.cpp @@ -80,7 +80,8 @@ int hidden_wrong(int x) } return y; } -// CHECK-DAG: error: verification failed: hidden_wrong [{{.*}}y [ssa=y#2_1] [type=i32] = 5, y [ssa=y#2_2] [type=i32] = 6, y [ssa=y_1] [type=i32] = {{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: hidden_wrong [postcondition]{{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: x = {{[0-9]+}}, y (line [[@LINE-8]]) = {{[0-9]+}}, y (line [[@LINE-6]]) = 5 -> 6, result = {{[0-9]+}} // A block may hide a parameter; the contract reads the parameter. int parameter_hidden(int x) @@ -107,7 +108,7 @@ int parameter_hidden_wrong(int x) } return r; } -// CHECK-DAG: error: verification failed: parameter_hidden_wrong [{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: parameter_hidden_wrong [postcondition]{{.*}}[reason=counterexample] // Each declaration starts uninitialized, whatever an earlier one with its // name held. From 8810d5a2765f91dd007035a9762e491050379e23 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:58 +0530 Subject: [PATCH 096/259] test: Expect failures as Clang diagnostics in local_object_unsupported.cpp. --- clang/test/Verify/suite/local_object_unsupported.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/local_object_unsupported.cpp b/clang/test/Verify/suite/local_object_unsupported.cpp index bbddcb2a4a..d68ac939fb 100644 --- a/clang/test/Verify/suite/local_object_unsupported.cpp +++ b/clang/test/Verify/suite/local_object_unsupported.cpp @@ -193,7 +193,7 @@ int flattened_nested_record() // VERIFY-DAG: error: unsupported_copy_source: unsupported aggregate initializer for an automatic object // VERIFY-DAG: error: return_local_address: raw address-of is unsupported until lexical lifetime and escape effects are modeled // VERIFY-DAG: error: return_local_array: array-to-pointer decay of automatic storage is unsupported until lexical lifetime and escape effects are modeled -// FAILS-DAG: error: verification failed: dereference_escaped_local [{{.*}}::postcondition@{{.*}}[reason=counterexample] +// FAILS-DAG: error: verification failed: dereference_escaped_local [postcondition]{{.*}}[reason=counterexample] // VERIFY-DAG: error: raw_pointer_into_local_array: raw address-of is unsupported until lexical lifetime and escape effects are modeled // VERIFY-DAG: error: whole_object_pointer_argument: raw address-of is unsupported until lexical lifetime and escape effects are modeled // VERIFY-DAG: error: provenance_pointer_field: storing a provenance-bearing pointer in an automatic object is unsupported From b2487a28a96195c315827689d0a866025643b705 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:58 +0530 Subject: [PATCH 097/259] test: Expect failures as Clang diagnostics in local_record_arguments.cpp. --- clang/test/Verify/suite/local_record_arguments.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/local_record_arguments.cpp b/clang/test/Verify/suite/local_record_arguments.cpp index 440e4be597..690b559bb9 100644 --- a/clang/test/Verify/suite/local_record_arguments.cpp +++ b/clang/test/Verify/suite/local_record_arguments.cpp @@ -133,7 +133,8 @@ int wrong() bump(c); return c.n; } -// CHECK-DAG: error: verification failed: wrong [{{.*}}::postcondition@[[@LINE-8]]:37] (counterexample: result [ssa=__result_1] [type=i32] = 1; +// CHECK-DAG: :[[@LINE-8]]:37: error: verification failed: wrong [postcondition] +// CHECK-DAG: note: counterexample: {{.*}}result = 1{{( ->|,|$)}} // A member and an element of a local, and the address of a field. int member() @@ -368,7 +369,7 @@ int same_local() pair_bump(a, a); return a.n; } -// CHECK-DAG: error: verification failed: same_local [{{.*}}::aliasing@[[@LINE-3]]:3] +// CHECK-DAG: :[[@LINE-3]]:3: error: verification failed: same_local [aliasing] // A callee that writes its record before reading it needs none of it // initialized: c.limit never is. One that may read it needs every field. From 6d6ee0b94fb4da5890231e616999b4bb9fc9ef26 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:59 +0530 Subject: [PATCH 098/259] test: Expect failures as Clang diagnostics in lookup_tables.cpp. --- clang/test/Verify/suite/lookup_tables.cpp | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/clang/test/Verify/suite/lookup_tables.cpp b/clang/test/Verify/suite/lookup_tables.cpp index 07954ebb14..a292f1bfbe 100644 --- a/clang/test/Verify/suite/lookup_tables.cpp +++ b/clang/test/Verify/suite/lookup_tables.cpp @@ -34,7 +34,8 @@ int popcount8_wrong(uint8_t x) { return NibbleBits[x & 15] + NibbleBits[x >> 4]; } -// CHECK-DAG: error: verification failed: popcount8_wrong [{{.*}}x [ssa=x_0] [type=u8] = 255{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: popcount8_wrong {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}x = 255{{( ->|,|$)}} // An index outside the table is undefined. int nibble_bits(int x) @@ -42,7 +43,7 @@ int nibble_bits(int x) { return NibbleBits[x]; } -// CHECK-DAG: error: verification failed: nibble_bits [{{.*}}::bounds@[[@LINE-2]]:{{.*}}[reason=counterexample] +// CHECK-DAG: :[[@LINE-2]]:{{[0-9]+}}: error: verification failed: nibble_bits [bounds]{{.*}}[reason=counterexample] int nibble_bits_inside(int x) cv::pre(0 <= x && x < 16) @@ -58,7 +59,8 @@ int nibble_bits_before(int x) { return NibbleBits[x - 1]; } -// CHECK-DAG: error: verification failed: nibble_bits_before [{{.*}}::bounds@[[@LINE-2]]:{{.*}}x [ssa=x_0] [type=i32] = 0{{.*}}[reason=counterexample] +// CHECK-DAG: :[[@LINE-2]]:{{[0-9]+}}: error: verification failed: nibble_bits_before [bounds] {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}x = 0{{( ->|,|$)}} // A table declared in a function, two-dimensional, with elements its // initializer leaves zero. @@ -78,7 +80,8 @@ int add_mod3_wrong(int a, int b) static constexpr int Sum[3][3] = {{0, 1, 2}, {1, 2, 0}, {2, 1, 0}}; return Sum[a][b]; } -// CHECK-DAG: error: verification failed: add_mod3_wrong [{{.*}}a [ssa=a_0] [type=i32] = 2, b [ssa=b_0] [type=i32] = {{1|2}}{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: add_mod3_wrong {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}a = 2{{( ->|,|$)}}{{.*}}b = {{1|2}}{{( ->|,|$)}} int row_outside(int a) cv::pre(0 <= a && a < 3) @@ -87,7 +90,7 @@ int row_outside(int a) static constexpr int Sum[3][3] = {{0, 1, 2}, {1, 2, 0}, {2, 0, 1}}; return Sum[a][3]; } -// CHECK-DAG: error: verification failed: row_outside [{{.*}}::bounds@[[@LINE-2]]:{{.*}}[reason=counterexample] +// CHECK-DAG: :[[@LINE-2]]:{{[0-9]+}}: error: verification failed: row_outside [bounds]{{.*}}[reason=counterexample] // Rows of four: the element [r][c] is at 4 * r + c. static constexpr uint8_t Rows[2][4] = {{1, 2, 3, 4}, {5, 6, 7, 8}}; @@ -106,7 +109,8 @@ int row_major_wrong(int r, int c) { return Rows[r][c]; } -// CHECK-DAG: error: verification failed: row_major_wrong [{{.*}}r [ssa=r_0] [type=i32] = 1{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: row_major_wrong {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}r = 1{{( ->|,|$)}} constexpr int Primes[8] = {2, 3, 5, 7, 11}; @@ -133,7 +137,8 @@ char hex_digit_wrong(int d) { return "0123456789abcdef"[d + 1]; } -// CHECK-DAG: error: verification failed: hex_digit_wrong [{{.*}}::bounds@[[@LINE-2]]:{{.*}}d [ssa=d_0] [type=i32] = 16{{.*}}[reason=counterexample] +// CHECK-DAG: :[[@LINE-2]]:{{[0-9]+}}: error: verification failed: hex_digit_wrong [bounds] {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}d = 16{{( ->|,|$)}} // The last element of a literal is its terminating zero, and each element is // a value of its character type: '\xff' is -1 as a signed char. @@ -195,7 +200,8 @@ bool upper_at_wrong(int c) { return Ascii::IsUpper[c]; } -// CHECK-DAG: error: verification failed: upper_at_wrong [{{.*}}c [ssa=c_0] [type=i32] = 2{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: upper_at_wrong {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}c = 2{{( ->|,|$)}} // Contracts and ghost code read tables too. int first_prime() From abd429080a457bb4dafea3000ad87c01571dcb61 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:25:59 +0530 Subject: [PATCH 099/259] test: Expect failures as Clang diagnostics in loop_forms.cpp. --- clang/test/Verify/suite/loop_forms.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/clang/test/Verify/suite/loop_forms.cpp b/clang/test/Verify/suite/loop_forms.cpp index 7e9205b72e..bc801fab79 100644 --- a/clang/test/Verify/suite/loop_forms.cpp +++ b/clang/test/Verify/suite/loop_forms.cpp @@ -45,7 +45,8 @@ int stop_at_three_wrong(int n) cv::decreases(n - i); return i; } -// CHECK-DAG: error: verification failed: stop_at_three_wrong [{{.*}}n [ssa=n_0] [type=i32] = {{[4-9]|[1-9][0-9]+}}{{[,;]}}{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: stop_at_three_wrong {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}n = {{[4-9]|[1-9][0-9]+}}{{( ->|,|$)}} // A break in the first iteration skips the loop. int first_break(int x) @@ -74,7 +75,8 @@ int first_break_wrong(int x) } while (false); return r; } -// CHECK-DAG: error: verification failed: first_break_wrong [{{.*}}x [ssa=x_0] [type=i32] = {{[1-9][0-9]*}}{{[,;]}}{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: first_break_wrong {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}x = {{[1-9][0-9]*}}{{( ->|,|$)}} int count_odd(int n) cv::pre(1 <= n && n <= 100) @@ -360,7 +362,7 @@ int pairs_wrong(int n) } return j; } -// CHECK-DAG: error: verification failed: pairs_wrong [{{.*}}::postcondition@{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: pairs_wrong [postcondition]{{.*}}[reason=counterexample] int ordered(int x) cv::pre(0 <= x && x < 100) From cad8ba322a3ae9c6f25654ef505ab759e2a95b48 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:00 +0530 Subject: [PATCH 100/259] test: Expect failures as Clang diagnostics in loop_frames.cpp. --- clang/test/Verify/suite/loop_frames.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/clang/test/Verify/suite/loop_frames.cpp b/clang/test/Verify/suite/loop_frames.cpp index 301c7eda9e..a294ff983a 100644 --- a/clang/test/Verify/suite/loop_frames.cpp +++ b/clang/test/Verify/suite/loop_frames.cpp @@ -37,7 +37,7 @@ void writes_input(int *a, int *b, int n) b[0] = i; } } -// CHECK-DAG: error: verification failed: writes_input [{{.*}}::postcondition@ +// CHECK-DAG: error: verification failed: writes_input [postcondition] // The loop writes only a[0..n), so a[n] keeps its value. void keeps_tail(int *a, int n) @@ -68,7 +68,7 @@ void loses_tail(int *a, int n) a[i] = 0; } } -// CHECK-DAG: error: verification failed: loses_tail [{{.*}}::postcondition@ +// CHECK-DAG: error: verification failed: loses_tail [postcondition] // Read in each iteration, a[0 : i] is the prefix written so far. void untouched_suffix(int *a, int n) @@ -100,7 +100,7 @@ void writes_ahead(int *a, int n) a[i + 1] = 0; } } -// CHECK-DAG: error: verification failed: writes_ahead [{{.*}}::frame@[[@LINE-6]]:25] +// CHECK-DAG: :[[@LINE-6]]:25: error: verification failed: writes_ahead [frame] // A continue ends the iteration, so the frame is checked there too. void writes_then_continues(int *a, int *b, int n) @@ -119,7 +119,7 @@ void writes_then_continues(int *a, int *b, int n) a[i] = 0; } } -// CHECK-DAG: error: verification failed: writes_then_continues [{{.*}}::frame@[[@LINE-10]]:25] +// CHECK-DAG: :[[@LINE-10]]:25: error: verification failed: writes_then_continues [frame] void set(int *x) cppverify::pre(x != nullptr) @@ -198,7 +198,7 @@ void counts_wrongly(int *count, int *a, int n) *a = i; } } -// CHECK-DAG: error: verification failed: counts_wrongly [{{.*}}::postcondition@ +// CHECK-DAG: error: verification failed: counts_wrongly [postcondition] // A store's object is found from its address: a pointer walking through a // stays in a, so b keeps its value. @@ -249,7 +249,7 @@ void chosen_writes_b(int *a, int *b, int n, bool first) p[i] = 0; } } -// CHECK-DAG: error: verification failed: chosen_writes_b [{{.*}}::postcondition@ +// CHECK-DAG: error: verification failed: chosen_writes_b [postcondition] // With aliases(a, b), a may be b. void aliased_writes(int *a, int *b, int n) @@ -265,7 +265,7 @@ void aliased_writes(int *a, int *b, int n) a[i] = 0; } } -// CHECK-DAG: error: verification failed: aliased_writes [{{.*}}::postcondition@ +// CHECK-DAG: error: verification failed: aliased_writes [postcondition] // IR: fn untouched_suffix // IR: while From 04d651e37deb4715fb497b90e73d4018b925be97 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:00 +0530 Subject: [PATCH 101/259] test: Expect failures as Clang diagnostics in loop_initialization.cpp. --- clang/test/Verify/suite/loop_initialization.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/test/Verify/suite/loop_initialization.cpp b/clang/test/Verify/suite/loop_initialization.cpp index be551b7d30..77c1a32e67 100644 --- a/clang/test/Verify/suite/loop_initialization.cpp +++ b/clang/test/Verify/suite/loop_initialization.cpp @@ -77,7 +77,7 @@ int partially_filled() } return a[3]; } -// CHECK-DAG: error: verification failed: partially_filled [{{.*}}::initialization@[[@LINE-2]]:3] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: partially_filled [initialization] // Nor is one it reads before writing. int read_first() @@ -93,7 +93,7 @@ int read_first() } return 0; } -// CHECK-DAG: error: verification failed: read_first [{{.*}}::initialization@[[@LINE-5]]:7] +// CHECK-DAG: :[[@LINE-5]]:7: error: verification failed: read_first [initialization] // Reading p[i] in an invariant bounds i at the head. int last(const int *p, int n) @@ -144,4 +144,4 @@ void overrun() i = i + 1; } } -// CHECK-DAG: error: verification failed: overrun [{{.*}}::dereference@[[@LINE-6]]:31#2] +// CHECK-DAG: :[[@LINE-6]]:31: error: verification failed: overrun [dereference] From 0742050addd058faabcf76dffbde79c484dced74 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:01 +0530 Subject: [PATCH 102/259] test: Expect failures as Clang diagnostics in loop_local_frames.cpp. --- clang/test/Verify/suite/loop_local_frames.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/loop_local_frames.cpp b/clang/test/Verify/suite/loop_local_frames.cpp index 9e8c660749..30e9871817 100644 --- a/clang/test/Verify/suite/loop_local_frames.cpp +++ b/clang/test/Verify/suite/loop_local_frames.cpp @@ -184,7 +184,7 @@ int overwritten() } return a[3]; } -// CHECK-DAG: error: verification failed: overwritten [{{.*}}::postcondition@ +// CHECK-DAG: error: verification failed: overwritten [postcondition] // Nor is a local written through a reference to it. int through_reference() @@ -202,4 +202,4 @@ int through_reference() } return x; } -// CHECK-DAG: error: verification failed: through_reference [{{.*}}::postcondition@ +// CHECK-DAG: error: verification failed: through_reference [postcondition] From 81f6a91388d543e6e9e74215ae4507a5433d6699 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:01 +0530 Subject: [PATCH 103/259] test: Expect failures as Clang diagnostics in loop_termination.cpp. --- clang/test/Verify/suite/loop_termination.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/loop_termination.cpp b/clang/test/Verify/suite/loop_termination.cpp index 7b8d1ea13b..153f9556c0 100644 --- a/clang/test/Verify/suite/loop_termination.cpp +++ b/clang/test/Verify/suite/loop_termination.cpp @@ -117,4 +117,4 @@ void refill(int &value, int n) if (n > 0) refill(value, n); } -// CHECK-DAG: error: verification failed: refill [{{.*}}::termination@118:5] +// CHECK-DAG: :118:5: error: verification failed: refill [termination] From 26dd41c8746fe083af6a2e2b4ce956dc69dea9ea Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:02 +0530 Subject: [PATCH 104/259] test: Expect failures as Clang diagnostics in max_failures.cpp. --- clang/test/Verify/suite/max_failures.cpp | 55 +++++++++++++----------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/clang/test/Verify/suite/max_failures.cpp b/clang/test/Verify/suite/max_failures.cpp index ee169ceb8d..cabc2fcdc3 100644 --- a/clang/test/Verify/suite/max_failures.cpp +++ b/clang/test/Verify/suite/max_failures.cpp @@ -58,39 +58,44 @@ int counted(int n) return c; } -// ONE: max_failures.cpp:23:3: error: verification failed: three_bugs [{{.*}}::division-by-zero@23:3] (counterexample: {{.*}}y [ssa=y_0] [type=i32] = 0{{.*}}) [backend=z3] [reason=counterexample] -// ONE-NEXT: max_failures.cpp:30:23: error: verification failed: one_bug [{{.*}}::postcondition@30:23] -// ONE-NEXT: max_failures.cpp:40:3: error: verification failed: dependent [{{.*}}::division-by-zero@40:3] -// ONE-NEXT: max_failures.cpp:49:23: error: verification failed: counted [{{.*}}::postcondition@49:23] -// ONE-NEXT: note: the counterexample's state at the loop at 53:3 is any state its invariants allow, not necessarily one an execution reaches +// ONE: max_failures.cpp:23:3: error: verification failed: three_bugs [division-by-zero] [backend=z3] [reason=counterexample] +// ONE: note: counterexample: {{.*}}y = 0{{( ->|,|$)}} +// ONE: max_failures.cpp:30:23: error: verification failed: one_bug [postcondition] +// ONE: max_failures.cpp:40:3: error: verification failed: dependent [division-by-zero] +// ONE: max_failures.cpp:49:23: error: verification failed: counted [postcondition] +// ONE: note: the counterexample's state at the loop at 53:3 is any state its invariants allow, not necessarily one an execution reaches // ONE-NEXT: note: no execution fails this check: every loop ends within 3 iterations, and unrolling proves it there; the loops' invariants are too weak for an unbounded proof // ONE-NEXT: Summary: 4 failed // The overflow's counterexample divides by y, which is not zero. -// TWO: max_failures.cpp:23:3: error: verification failed: three_bugs [{{.*}}::division-by-zero@23:3] -// TWO-NEXT: max_failures.cpp:24:3: error: verification failed: three_bugs [{{.*}}::overflow@24:3] (counterexample: {{.*}}y [ssa=y_0] [type=i32] = {{-?[1-9][0-9]*}}) [backend=z3] [reason=counterexample] -// TWO-NEXT: max_failures.cpp:30:23: error: verification failed: one_bug [{{.*}}::postcondition@30:23] -// TWO-NEXT: max_failures.cpp:40:3: error: verification failed: dependent [{{.*}}::division-by-zero@40:3] -// TWO-NEXT: max_failures.cpp:49:23: error: verification failed: counted [{{.*}}::postcondition@49:23] -// TWO-NEXT: note: the counterexample's state at the loop at 53:3 is any state its invariants allow, not necessarily one an execution reaches +// TWO: max_failures.cpp:23:3: error: verification failed: three_bugs [division-by-zero] +// TWO: max_failures.cpp:24:3: error: verification failed: three_bugs [overflow] [backend=z3] [reason=counterexample] +// TWO: note: counterexample: {{.*}}y = {{-?[1-9][0-9]*}}{{( ->|,|$)}} +// TWO: max_failures.cpp:30:23: error: verification failed: one_bug [postcondition] +// TWO: max_failures.cpp:40:3: error: verification failed: dependent [division-by-zero] +// TWO: max_failures.cpp:49:23: error: verification failed: counted [postcondition] +// TWO: note: the counterexample's state at the loop at 53:3 is any state its invariants allow, not necessarily one an execution reaches // TWO-NEXT: note: no execution fails this check: every loop ends within 3 iterations, and unrolling proves it there; the loops' invariants are too weak for an unbounded proof -// TWO-NEXT: max_failures.cpp:50:23: error: verification failed: counted [{{.*}}::postcondition@50:23] -// TWO-NEXT: note: the counterexample's state at the loop at 53:3 is any state its invariants allow, not necessarily one an execution reaches -// TWO-NEXT: note: an execution fails this check with no iteration of any loop (counterexample: {{.*}}n [ssa=n_0] [type=i32] = 0{{.*}}) +// TWO-NEXT: max_failures.cpp:50:23: error: verification failed: counted [postcondition] +// TWO: note: the counterexample's state at the loop at 53:3 is any state its invariants allow, not necessarily one an execution reaches +// TWO-NEXT: note: an execution fails this check with no iteration of any loop (counterexample: {{.*}}n = 0{{.*}}) // TWO-NEXT: Summary: 4 failed -// ALL: max_failures.cpp:23:3: error: verification failed: three_bugs [{{.*}}::division-by-zero@23:3] -// ALL-NEXT: max_failures.cpp:24:3: error: verification failed: three_bugs [{{.*}}::overflow@24:3] (counterexample: {{.*}}y [ssa=y_0] [type=i32] = {{-?[1-9][0-9]*}}) -// ALL-NEXT: max_failures.cpp:20:23: error: verification failed: three_bugs [{{.*}}::postcondition@20:23] (counterexample: {{.*}}y [ssa=y_0] [type=i32] = {{-?[1-9][0-9]*}}; -// ALL-NEXT: max_failures.cpp:21:23: error: verification failed: three_bugs [{{.*}}::postcondition@21:23] (counterexample: {{.*}}y [ssa=y_0] [type=i32] = {{-?[1-9][0-9]*}}; -// ALL-NEXT: max_failures.cpp:30:23: error: verification failed: one_bug [{{.*}}::postcondition@30:23] -// ALL-NEXT: max_failures.cpp:40:3: error: verification failed: dependent [{{.*}}::division-by-zero@40:3] -// ALL-NEXT: max_failures.cpp:49:23: error: verification failed: counted [{{.*}}::postcondition@49:23] -// ALL-NEXT: note: the counterexample's state at the loop at 53:3 is any state its invariants allow, not necessarily one an execution reaches +// ALL: max_failures.cpp:23:3: error: verification failed: three_bugs [division-by-zero] +// ALL: max_failures.cpp:24:3: error: verification failed: three_bugs [overflow] +// ALL: note: counterexample: {{.*}}y = {{-?[1-9][0-9]*}}{{( ->|,|$)}} +// ALL: max_failures.cpp:20:23: error: verification failed: three_bugs [postcondition] +// ALL: note: counterexample: {{.*}}y = {{-?[1-9][0-9]*}}{{( ->|,|$)}} +// ALL: max_failures.cpp:21:23: error: verification failed: three_bugs [postcondition] +// ALL: note: counterexample: {{.*}}y = {{-?[1-9][0-9]*}}{{( ->|,|$)}} +// ALL: max_failures.cpp:30:23: error: verification failed: one_bug [postcondition] +// ALL: max_failures.cpp:40:3: error: verification failed: dependent [division-by-zero] +// ALL: max_failures.cpp:49:23: error: verification failed: counted [postcondition] +// ALL: note: the counterexample's state at the loop at 53:3 is any state its invariants allow, not necessarily one an execution reaches // ALL-NEXT: note: no execution fails this check: every loop ends within 3 iterations, and unrolling proves it there; the loops' invariants are too weak for an unbounded proof -// ALL-NEXT: max_failures.cpp:50:23: error: verification failed: counted [{{.*}}::postcondition@50:23] -// ALL-NEXT: note: the counterexample's state at the loop at 53:3 is any state its invariants allow, not necessarily one an execution reaches -// ALL-NEXT: note: an execution fails this check with no iteration of any loop (counterexample: {{.*}}n [ssa=n_0] [type=i32] = 0{{.*}}) +// ALL-NEXT: max_failures.cpp:50:23: error: verification failed: counted [postcondition] +// ALL: note: the counterexample's state at the loop at 53:3 is any state its invariants allow, not necessarily one an execution reaches +// ALL-NEXT: note: an execution fails this check with no iteration of any loop (counterexample: {{.*}}n = 0{{.*}}) // ALL-NEXT: Summary: 4 failed // JSON-COUNT-4: "function":"three_bugs" From 06d73884a208679f60c60dcafe8fbf7136278159 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:02 +0530 Subject: [PATCH 105/259] test: Expect failures as Clang diagnostics in member_functions.cpp. --- clang/test/Verify/suite/member_functions.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/clang/test/Verify/suite/member_functions.cpp b/clang/test/Verify/suite/member_functions.cpp index e4587cdae9..d03bb2c18f 100644 --- a/clang/test/Verify/suite/member_functions.cpp +++ b/clang/test/Verify/suite/member_functions.cpp @@ -117,10 +117,11 @@ struct Counter { // CHECK-DAG: Verified: Counter::peek_counted [backend=z3] // CHECK-DAG: Verified: Counter::zero [backend=z3] -// CHECK-DAG: error: verification failed: Counter::bad [{{.*}}::frame@{{[0-9]+}}:11] (counterexample: this [ssa=this_0] [type=pointer] = +// CHECK-DAG: :{{[0-9]+}}:11: error: verification failed: Counter::bad [frame] +// CHECK-DAG: note: counterexample: {{.*}}this = // A const member function writes only its own storage, mutable fields // included, unless its modifies lists them. -// CHECK-DAG: error: verification failed: Counter::peek_bad [{{.*}}::frame@ +// CHECK-DAG: error: verification failed: Counter::peek_bad [frame] void Counter::set(int v) { @@ -206,7 +207,7 @@ void cleared_narrow(Counter &c) { c.reset(); } -// CHECK-DAG: error: verification failed: cleared_narrow [{{.*}}::frame@[[@LINE-2]]:5] +// CHECK-DAG: :[[@LINE-2]]:5: error: verification failed: cleared_narrow [frame] // `this` and a mutable or read parameter are distinct objects by default. void self_copy(Counter &c) @@ -214,7 +215,7 @@ void self_copy(Counter &c) { c.copy_from(c); } -// CHECK-DAG: error: verification failed: self_copy [{{.*}}::aliasing@[[@LINE-2]]:5] +// CHECK-DAG: :[[@LINE-2]]:5: error: verification failed: self_copy [aliasing] int self_plus(const Counter &c) cppverify::pre(-1000 < c.n && c.n < 1000) From ef7b278591b614580d7fe83e74d80c68a0e8a4e5 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:03 +0530 Subject: [PATCH 106/259] test: Expect failures as Clang diagnostics in member_operators.cpp. --- clang/test/Verify/suite/member_operators.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/test/Verify/suite/member_operators.cpp b/clang/test/Verify/suite/member_operators.cpp index f8251fcca9..a21e20ba44 100644 --- a/clang/test/Verify/suite/member_operators.cpp +++ b/clang/test/Verify/suite/member_operators.cpp @@ -119,7 +119,7 @@ int self_add() a += a; return a.cents; } -// CHECK-DAG: error: verification failed: self_add [{{.*}}::aliasing@[[@LINE-3]] +// CHECK-DAG: :[[@LINE-3]]:{{[0-9]+}}: error: verification failed: self_add [aliasing] // The reference such an operator returns is no value yet. int chained() @@ -205,7 +205,7 @@ void spoil(Level &l) { l.value = 500; } -// CHECK-DAG: error: verification failed: spoil [{{.*}}::type-invariant@ +// CHECK-DAG: error: verification failed: spoil [type-invariant] int spoiled_argument() cppverify::post(true) @@ -215,7 +215,7 @@ int spoiled_argument() int v = read(l); return v; } -// CHECK-DAG: error: verification failed: spoiled_argument [{{.*}}::type-invariant@[[@LINE-3]] +// CHECK-DAG: :[[@LINE-3]]:{{[0-9]+}}: error: verification failed: spoiled_argument [type-invariant] // A null pointer addresses no object, whose invariant would be due. int none() @@ -254,4 +254,4 @@ int first_through(const Span &s) int v = s.first(); return v; } -// CHECK-DAG: error: verification failed: first_through [{{.*}}::bounds@[[@LINE-3]] +// CHECK-DAG: :[[@LINE-3]]:{{[0-9]+}}: error: verification failed: first_through [bounds] From 5f8f267110c7dee22f522220ec72ed4b5116c501 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:03 +0530 Subject: [PATCH 107/259] test: Expect failures as Clang diagnostics in memory_objects.cpp. --- clang/test/Verify/suite/memory_objects.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/clang/test/Verify/suite/memory_objects.cpp b/clang/test/Verify/suite/memory_objects.cpp index 7d698da707..86485432a2 100644 --- a/clang/test/Verify/suite/memory_objects.cpp +++ b/clang/test/Verify/suite/memory_objects.cpp @@ -16,7 +16,7 @@ int beyond_single(const int *p) { return p[1]; } -// CHECK-DAG: error: verification failed: beyond_single [{{.*}}::bounds@ +// CHECK-DAG: error: verification failed: beyond_single [bounds] int through_copy(const int *p, int n) cppverify::pre(valid(p, n) && n >= 1 && n < 100) @@ -24,7 +24,7 @@ int through_copy(const int *p, int n) const int *q = p; return q[n]; } -// CHECK-DAG: error: verification failed: through_copy [{{.*}}::bounds@ +// CHECK-DAG: error: verification failed: through_copy [bounds] int through_selection(const int *p, const int *q, bool c) cppverify::pre(p != nullptr && q != nullptr) @@ -32,7 +32,7 @@ int through_selection(const int *p, const int *q, bool c) const int *r = c ? p : q; return r[1]; } -// CHECK-DAG: error: verification failed: through_selection [{{.*}}::bounds@ +// CHECK-DAG: error: verification failed: through_selection [bounds] int after_rebinding(const int *p, int n) cppverify::pre(valid(p, n) && n >= 1 && n < 100) @@ -40,7 +40,7 @@ int after_rebinding(const int *p, int n) p = p + n; return p[0]; } -// CHECK-DAG: error: verification failed: after_rebinding [{{.*}}::bounds@ +// CHECK-DAG: error: verification failed: after_rebinding [bounds] void loop_overrun(int *p, int n) cppverify::pre(valid(p, n) && n >= 1 && n < 100) @@ -53,14 +53,14 @@ void loop_overrun(int *p, int n) p[i] = 0; } } -// CHECK-DAG: error: verification failed: loop_overrun [{{.*}}::bounds@ +// CHECK-DAG: error: verification failed: loop_overrun [bounds] int empty_extent(const int *p, int n) cppverify::pre(valid(p, n) && n == 0 && p != nullptr) { return p[0]; } -// CHECK-DAG: error: verification failed: empty_extent [{{.*}}::bounds@ +// CHECK-DAG: error: verification failed: empty_extent [bounds] bool step_too_far(const int *p) cppverify::pre(valid(p, 2)) @@ -68,7 +68,7 @@ bool step_too_far(const int *p) const int *q = p + 3; return q == p; } -// CHECK-DAG: error: verification failed: step_too_far [{{.*}}::bounds@ +// CHECK-DAG: error: verification failed: step_too_far [bounds] bool one_past(const int *p) cppverify::pre(valid(p, 2)) @@ -134,7 +134,7 @@ int past_external(int value) int *cell = external_cell(value); return cell[1]; } -// CHECK-DAG: error: verification failed: past_external [{{.*}}::bounds@ +// CHECK-DAG: error: verification failed: past_external [bounds] struct Pair { int first; @@ -147,4 +147,4 @@ int past_object(const Pair *p, const Pair *q) { return (p + 1)->second; } -// CHECK-DAG: error: verification failed: past_object [{{.*}}::bounds@ +// CHECK-DAG: error: verification failed: past_object [bounds] From e07257f93029e45b53a4b73fae76f766df8ab767 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:04 +0530 Subject: [PATCH 108/259] test: Expect failures as Clang diagnostics in mutual_recursion.cpp. --- clang/test/Verify/suite/mutual_recursion.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/mutual_recursion.cpp b/clang/test/Verify/suite/mutual_recursion.cpp index ff3fa2bcd1..6efc5bf2ee 100644 --- a/clang/test/Verify/suite/mutual_recursion.cpp +++ b/clang/test/Verify/suite/mutual_recursion.cpp @@ -78,5 +78,5 @@ int ping(int n) return 0; return pong(n - 1); } -// CHECK-DAG: error: verification failed: pong [{{.*}}::termination@{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: pong [termination]{{.*}}[reason=counterexample] // CHECK-DAG: Unresolved: ping {{.*}}[reason=callee.contract] (relies on the contract of pong, which is not established) From 82d0a515f91857c64b62e8b2c2c1425df04859d2 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:04 +0530 Subject: [PATCH 109/259] test: Expect failures as Clang diagnostics in nested_quantifier_counterexamples.cpp. --- .../suite/nested_quantifier_counterexamples.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/clang/test/Verify/suite/nested_quantifier_counterexamples.cpp b/clang/test/Verify/suite/nested_quantifier_counterexamples.cpp index cec19c5b3d..a83eaf27e1 100644 --- a/clang/test/Verify/suite/nested_quantifier_counterexamples.cpp +++ b/clang/test/Verify/suite/nested_quantifier_counterexamples.cpp @@ -14,7 +14,8 @@ cppverify::proof void every_has_larger(seq s) cppverify::check(cppverify::forall(i, !(0 <= i && i < s.len()) || cppverify::exists(j, 0 <= j && j < s.len() && s[j] > s[i]))); } -// CHECK-DAG: error: verification failed: every_has_larger [{{.*}}::assertion@[[@LINE-3]]:3] (counterexample: s [ssa=s_0] [type=seq] = [{{.*}}]) [backend=z3] [reason=counterexample] +// CHECK-DAG: :[[@LINE-3]]:3: error: verification failed: every_has_larger [assertion] [backend=z3] [reason=counterexample] +// CHECK-DAG: note: counterexample: s = [{{.*}}] cppverify::proof void every_has_no_smaller(seq s) cppverify::pre(s.len() >= 1 && s.len() <= 3) @@ -31,7 +32,7 @@ int max_index(const int *a, int n) { return 0; } -// CHECK-DAG: error: verification failed: max_index [{{.*}}::postcondition@{{.*}}] (counterexample: {{.*}}) [backend=z3] [reason=counterexample] +// CHECK-DAG: error: verification failed: max_index [postcondition] [backend=z3] [reason=counterexample] // Distinct elements repeat nowhere. cppverify::proof void some_repeated(seq s) @@ -41,7 +42,8 @@ cppverify::proof void some_repeated(seq s) cppverify::exists(j, 0 <= j && j < s.len() && i != j && s[i] == s[j]))); } -// CHECK-DAG: error: verification failed: some_repeated [{{.*}}::assertion@[[@LINE-4]]:3] (counterexample: s [ssa=s_0] [type=seq] = [{{.*}}]) [backend=z3] [reason=counterexample] +// CHECK-DAG: :[[@LINE-4]]:3: error: verification failed: some_repeated [assertion] [backend=z3] [reason=counterexample] +// CHECK-DAG: note: counterexample: s = [{{.*}}] // A product of bound variables is outside Presburger arithmetic, but a // witness decides the claim: no j makes 0 * j == 6. @@ -50,7 +52,8 @@ cppverify::proof void not_all_products_even(int n) { cppverify::check(cppverify::forall(i, cppverify::exists(j, i * j == 2 * n))); } -// CHECK-DAG: error: verification failed: not_all_products_even [{{.*}}::assertion@[[@LINE-2]]:3] (counterexample: n [ssa=n_0] [type=i32] = 3) [backend=z3] [reason=counterexample] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: not_all_products_even [assertion] [backend=z3] [reason=counterexample] +// CHECK-DAG: note: counterexample: n = 3 // Refuting this needs every value of i: no witness can, and i * j is no // linear term. From ec47f44f3aabe5a79c8b3383644c069e7e29835a Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:05 +0530 Subject: [PATCH 110/259] test: Expect failures as Clang diagnostics in old_loop_invariant_definedness_fail.cpp. --- .../Verify/suite/old_loop_invariant_definedness_fail.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/test/Verify/suite/old_loop_invariant_definedness_fail.cpp b/clang/test/Verify/suite/old_loop_invariant_definedness_fail.cpp index 0643639d8c..7d46cf3ff5 100644 --- a/clang/test/Verify/suite/old_loop_invariant_definedness_fail.cpp +++ b/clang/test/Verify/suite/old_loop_invariant_definedness_fail.cpp @@ -34,7 +34,7 @@ int reject_old_entry_null_dereference(int *pointer, int *replacement) return 0; } -// CHECK-DAG: error: verification failed: reject_old_entry_overflow [{{.*}}::overflow@ -// CHECK-DAG: error: verification failed: reject_quantified_old_entry_overflow [{{.*}}::overflow@ -// CHECK-DAG: error: verification failed: reject_old_entry_null_dereference [{{.*}}::dereference@ +// CHECK-DAG: error: verification failed: reject_old_entry_overflow [overflow] +// CHECK-DAG: error: verification failed: reject_quantified_old_entry_overflow [overflow] +// CHECK-DAG: error: verification failed: reject_old_entry_null_dereference [dereference] From 583bad823df524c790d081c06e0a38594d0a0504 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:05 +0530 Subject: [PATCH 111/259] test: Expect failures as Clang diagnostics in out_parameters.cpp. --- clang/test/Verify/suite/out_parameters.cpp | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/clang/test/Verify/suite/out_parameters.cpp b/clang/test/Verify/suite/out_parameters.cpp index a72b5e35d2..ccd0cd7358 100644 --- a/clang/test/Verify/suite/out_parameters.cpp +++ b/clang/test/Verify/suite/out_parameters.cpp @@ -130,7 +130,7 @@ int read_before_written() int v = r; return v; } -// CHECK: error: verification failed: read_before_written {{.*}}initialization@[[@LINE-3]]:3 +// CHECK: :[[@LINE-3]]:3: error: verification failed: read_before_written [initialization] int *fresh() cv::post(cv::result != nullptr) @@ -213,8 +213,8 @@ int reads_after_failed_get() try_get(a[0], false); return a[0]; } -// CHECK: error: verification failed: reads_after_failed_get {{.*}}initialization@[[@LINE-2]]:3 -// NOUB: error: verification failed: reads_after_failed_get {{.*}}initialization@[[@LINE-3]]:3 +// CHECK: :[[@LINE-2]]:3: error: verification failed: reads_after_failed_get [initialization] +// NOUB: :[[@LINE-3]]:3: error: verification failed: reads_after_failed_get [initialization] // Written, then read: still an out-parameter. void write_then_update(int &x) @@ -431,7 +431,7 @@ int reads_unmade() make_first(p); return p.b; } -// CHECK: error: verification failed: reads_unmade {{.*}}initialization@[[@LINE-2]]:3 +// CHECK: :[[@LINE-2]]:3: error: verification failed: reads_unmade [initialization] // A postcondition about storage the function never writes speaks of the // caller's values: an input, initialized at entry. @@ -452,8 +452,8 @@ void set_if(int &x, bool c) if (c) x = 1; } -// CHECK: error: verification failed: set_if {{.*}}initialization@[[@LINE-5]]:14 -// NOUB: error: verification failed: set_if {{.*}}initialization@[[@LINE-6]]:14 +// CHECK: :[[@LINE-5]]:14: error: verification failed: set_if [initialization] +// NOUB: :[[@LINE-6]]:14: error: verification failed: set_if [initialization] // A loop writes on no path known before it runs. void zero_each(int &x, int n) @@ -481,7 +481,7 @@ int maybe_zeroed() zero_each(a[0], 0); return a[0]; } -// CHECK: error: verification failed: maybe_zeroed {{.*}}initialization@[[@LINE-2]]:3 +// CHECK: :[[@LINE-2]]:3: error: verification failed: maybe_zeroed [initialization] // A call that may write a cell keeps it initialized. int kept_through_call(int n) @@ -585,7 +585,7 @@ int init_in_loop_only(int n) } return a[0]; } -// CHECK: error: verification failed: init_in_loop_only {{.*}}initialization@[[@LINE-2]]:3 +// CHECK: :[[@LINE-2]]:3: error: verification failed: init_in_loop_only [initialization] void zero_rec(int &x, int n) cv::pre(n >= 0) @@ -698,7 +698,7 @@ void fill_three(int *b) { fill(b, 3); } -// CHECK: error: verification failed: fill_three {{.*}}initialization@[[@LINE-4]]:12 +// CHECK: :[[@LINE-4]]:12: error: verification failed: fill_three [initialization] // A member function that writes its object. struct Point { From 5772e2e1fd27d524e15051fe1eba4b772d345a89 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:06 +0530 Subject: [PATCH 112/259] test: Expect failures as Clang diagnostics in parallel_functions.test. --- clang/test/Verify/suite/parallel_functions.test | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/clang/test/Verify/suite/parallel_functions.test b/clang/test/Verify/suite/parallel_functions.test index 5af7fd5464..4122c6ec03 100644 --- a/clang/test/Verify/suite/parallel_functions.test +++ b/clang/test/Verify/suite/parallel_functions.test @@ -35,15 +35,15 @@ # CHECK: Verified: spec decreases: climb # CHECK-NEXT: error: spec decreases failed: diverge -# CHECK-NEXT: Verified: climb_zero [backend=z3] +# CHECK: Verified: climb_zero [backend=z3] # CHECK-NEXT: Unresolved: diverge_zero [backend=z3] [reason=spec.termination] # CHECK-NEXT: error: verification failed: off_by_one -# CHECK-NEXT: Unresolved: relies_on_off_by_one [backend=z3] [reason=callee.contract] +# CHECK: Unresolved: relies_on_off_by_one [backend=z3] [reason=callee.contract] # CHECK-NEXT: Verified: positive_identity [backend=z3] (its precondition is assumed, not checked, at calls from unverified unchecked_caller) # CHECK-NEXT: Verified: sum_to [backend=z3] # CHECK-NEXT: Verified: clear [backend=z3] -# CHECK-NEXT: error: verification failed: overflow [{{.*}}::overflow@ -# CHECK-NEXT: error: verification failed: two_failures [{{.*}}::assertion@72:3] -# CHECK-NEXT: Verified: both_ways [backend=z3] +# CHECK-NEXT: error: verification failed: overflow [overflow] +# CHECK: :72:3: error: verification failed: two_failures [assertion] +# CHECK: Verified: both_ways [backend=z3] # BUDGET: Unresolved: sum_to [backend=z3] [reason=solver.timeout] From be950905ce3a802922e85afbe78d7f40e9bf5fdd Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:06 +0530 Subject: [PATCH 113/259] test: Expect failures as Clang diagnostics in pointer_difference_null.cpp. --- clang/test/Verify/suite/pointer_difference_null.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/pointer_difference_null.cpp b/clang/test/Verify/suite/pointer_difference_null.cpp index 7ccb9c8e7d..df76fec608 100644 --- a/clang/test/Verify/suite/pointer_difference_null.cpp +++ b/clang/test/Verify/suite/pointer_difference_null.cpp @@ -47,7 +47,7 @@ long null_minus_object(const int *a, int n) const int *z = nullptr; return a - z; } -// CHECK-DAG: error: verification failed: null_minus_object [{{.*}}::pointer-difference@{{[0-9]+:[0-9]+}}] {{.*}}[reason=counterexample] +// CHECK-DAG: :{{[0-9]+:[0-9]+}}: error: verification failed: null_minus_object [pointer-difference] {{.*}}[reason=counterexample] // Either may be null while the other is not. long one_null(const int *a, const int *b) @@ -55,4 +55,4 @@ long one_null(const int *a, const int *b) { return a - b; } -// CHECK-DAG: error: verification failed: one_null [{{.*}}::pointer-difference@{{[0-9]+:[0-9]+}}] {{.*}}[reason=counterexample] +// CHECK-DAG: :{{[0-9]+:[0-9]+}}: error: verification failed: one_null [pointer-difference] {{.*}}[reason=counterexample] From f8c4bc07b91ab42fec9a279c16975ed465b2b803 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:07 +0530 Subject: [PATCH 114/259] test: Expect failures as Clang diagnostics in pointer_field_extents.cpp. --- .../test/Verify/suite/pointer_field_extents.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/clang/test/Verify/suite/pointer_field_extents.cpp b/clang/test/Verify/suite/pointer_field_extents.cpp index eae92770c9..8c4cdfe4fb 100644 --- a/clang/test/Verify/suite/pointer_field_extents.cpp +++ b/clang/test/Verify/suite/pointer_field_extents.cpp @@ -72,7 +72,8 @@ int past(const View *v) { return v->data[v->len]; } -// CHECK-DAG: error: verification failed: past [{{.*}}::bounds@[[@LINE-2]]:10] (counterexample: v->data [ssa=v->data_0] [type=pointer] = +// CHECK-DAG: :[[@LINE-2]]:10: error: verification failed: past [bounds] +// CHECK-DAG: note: counterexample: {{.*}}v->data = // Without an extent the field's buffer is no object of the function's. void unknown(Buf &b) @@ -81,7 +82,7 @@ void unknown(Buf &b) { b.data[0] = 1; } -// CHECK-DAG: error: verification failed: unknown [{{.*}}::bounds@[[@LINE-2]]:3] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: unknown [bounds] // The buffer is disjoint from its record, so the length keeps its value. int keeps_len(Buf &b) @@ -147,8 +148,8 @@ void too_long(int *p, int n) b.len = n + 1; zero(b); } -// CHECK-DAG: error: verification failed: too_long [{{.*}}::bounds@[[@LINE-2]]:3] -// BMC-DAG: error: verification failed: too_long [{{.*}}::bounds@[[@LINE-3]]:3] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: too_long [bounds] +// BMC-DAG: :[[@LINE-3]]:3: error: verification failed: too_long [bounds] // The extent is the field's at entry: a field given another pointer // addresses that pointer's object. @@ -170,7 +171,7 @@ void reseat_past(Buf &b, int *other) b.data = other; b.data[1] = 1; } -// CHECK-DAG: error: verification failed: reseat_past [{{.*}}::bounds@[[@LINE-2]]:3] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: reseat_past [bounds] // Two mutable buffers are disjoint by default, as two mutable parameters // are; two read-only ones may be one. @@ -198,7 +199,8 @@ void self_copy(Buf &b) { copy(b, b); } -// CHECK-DAG: error: verification failed: self_copy [{{.*}}::aliasing@[[@LINE-2]]:3] (counterexample: b.data [ssa=b->data_0] [type=pointer] = +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: self_copy [aliasing] +// CHECK-DAG: note: counterexample: {{.*}}b.data = int first_of_both(const View &a, const View &b) cppverify::pre(cppverify::valid(a.data, a.len) && cppverify::valid(b.data, b.len)) @@ -243,7 +245,7 @@ void nonempty_inside(Buf *b) { touch(b, &b->len, 1); } -// CHECK-DAG: error: verification failed: nonempty_inside [{{.*}}::aliasing@[[@LINE-2]]:3] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: nonempty_inside [aliasing] // Not yet: a field of an element (s->items[k].data). struct Shelf { From 03c88f7cc09fb568e78c63c9b341754673926498 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:07 +0530 Subject: [PATCH 115/259] test: Expect failures as Clang diagnostics in pointer_origins.cpp. --- clang/test/Verify/suite/pointer_origins.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/clang/test/Verify/suite/pointer_origins.cpp b/clang/test/Verify/suite/pointer_origins.cpp index 32a1dd9d9e..74e19f2384 100644 --- a/clang/test/Verify/suite/pointer_origins.cpp +++ b/clang/test/Verify/suite/pointer_origins.cpp @@ -114,7 +114,7 @@ void clear_chosen_loose(int *a, int *b, int n, bool s) q = q + 1; } } -// CHECK-DAG: error: verification failed: clear_chosen_loose [{{.*}}::bounds@[[@LINE-4]]:6] +// CHECK-DAG: :[[@LINE-4]]:6: error: verification failed: clear_chosen_loose [bounds] long choice_diff(int *a, int *b, bool first) cppverify::pre(a != nullptr && b != nullptr && first) @@ -140,7 +140,7 @@ void param_past(int *a) a = a + 2; a = a + 1; } -// CHECK-DAG: error: verification failed: param_past [{{.*}}::bounds@[[@LINE-2]]:9] +// CHECK-DAG: :[[@LINE-2]]:9: error: verification failed: param_past [bounds] // One past a single object, even where another object may start. void adjacent(int *a, int *b) @@ -150,7 +150,7 @@ void adjacent(int *a, int *b) int *q = a + 1; *q = 0; } -// CHECK-DAG: error: verification failed: adjacent [{{.*}}::bounds@[[@LINE-2]]:4] +// CHECK-DAG: :[[@LINE-2]]:4: error: verification failed: adjacent [bounds] // The walker does change its own object. void walk_changes(int *a, int n) @@ -167,7 +167,7 @@ void walk_changes(int *a, int n) q = q + 1; } } -// CHECK-DAG: error: verification failed: walk_changes [{{.*}}::postcondition@{{.*}}] (counterexample: {{.*}}) [backend=z3] [reason=counterexample] +// CHECK-DAG: error: verification failed: walk_changes [postcondition] [backend=z3] [reason=counterexample] // A chosen object may be either. void chosen_changes(int *a, int *b, bool first) @@ -183,7 +183,8 @@ void chosen_changes(int *a, int *b, bool first) *p = 5; } } -// CHECK-DAG: error: verification failed: chosen_changes [{{.*}}::postcondition@{{.*}}] (counterexample: {{.*}}first [ssa=first_0] [type=bool] = true{{.*}}) [backend=z3] [reason=counterexample] +// CHECK-DAG: error: verification failed: chosen_changes [postcondition] [backend=z3] [reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}first = true{{.*}} // The companion naming q's origin, and the generated invariants. // VCR-LABEL: fn clear_chosen From 5bab40036477310fb1344bc5ef080ac58a5f2955 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:08 +0530 Subject: [PATCH 116/259] test: Expect failures as Clang diagnostics in pointer_steps.cpp. --- clang/test/Verify/suite/pointer_steps.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/clang/test/Verify/suite/pointer_steps.cpp b/clang/test/Verify/suite/pointer_steps.cpp index 46d27b0b4d..f5318f2618 100644 --- a/clang/test/Verify/suite/pointer_steps.cpp +++ b/clang/test/Verify/suite/pointer_steps.cpp @@ -72,7 +72,8 @@ int too_far(const int *a, int n) q -= 2; return *q; } -// CHECK-DAG: error: verification failed: too_far [{{.*}}@[[@LINE-4]]:{{.*}}n [ssa=n_0] [type=i32] = 1{{[,;]}}{{.*}}[reason=counterexample] +// CHECK-DAG: :[[@LINE-4]]:{{[0-9]+}}: error: verification failed: too_far [{{[a-z-]+}}]{{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}n = 1{{( ->|,|$)}} int before_start(const int *a, int n) cv::pre(cv::valid(a, n) && 1 <= n && n <= 100) @@ -83,7 +84,7 @@ int before_start(const int *a, int n) ++q; return *q; } -// CHECK-DAG: error: verification failed: before_start [{{.*}}@[[@LINE-4]]:{{.*}}[reason=counterexample] +// CHECK-DAG: :[[@LINE-4]]:{{[0-9]+}}: error: verification failed: before_start [{{[a-z-]+}}]{{.*}}[reason=counterexample] // Stepping a null pointer is undefined. int *step_null(int *p) @@ -92,7 +93,8 @@ int *step_null(int *p) p += 1; return p; } -// CHECK-DAG: error: verification failed: step_null [{{.*}}::bounds@[[@LINE-3]]:{{.*}}p [ssa=p_0] [type=pointer] = 0{{.*}}[reason=counterexample] +// CHECK-DAG: :[[@LINE-3]]:{{[0-9]+}}: error: verification failed: step_null [bounds] {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}p = 0{{( ->|,|$)}} // A parameter may be stepped too; contracts read its entry value. void zero(int *p, int n) @@ -192,7 +194,7 @@ int ring_past(const Ring *r) ++q; return 0; } -// CHECK-DAG: error: verification failed: ring_past [{{.*}}@[[@LINE-3]]:{{.*}}[reason=counterexample] +// CHECK-DAG: :[[@LINE-3]]:{{[0-9]+}}: error: verification failed: ring_past [{{[a-z-]+}}]{{.*}}[reason=counterexample] // Unsupported: stepping a pointer to dynamic storage, and the value of a // step in an expression. From 025310d17f327563fe4235089bd0708c1d4208a2 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:08 +0530 Subject: [PATCH 117/259] test: Expect failures as Clang diagnostics in pointer_subobjects.cpp. --- .../test/Verify/suite/pointer_subobjects.cpp | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/clang/test/Verify/suite/pointer_subobjects.cpp b/clang/test/Verify/suite/pointer_subobjects.cpp index 40b778c243..492d1051bb 100644 --- a/clang/test/Verify/suite/pointer_subobjects.cpp +++ b/clang/test/Verify/suite/pointer_subobjects.cpp @@ -206,14 +206,16 @@ int past_end(const Outer *p, int i) { return p->buf[i]; } -// CHECK-DAG: error: verification failed: past_end [{{.*}}::bounds@[[@LINE-2]]:3] (counterexample: i [ssa=i_0] [type=i32] = 8, +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: past_end [bounds] +// CHECK-DAG: note: counterexample: {{.*}}i = 8{{( ->|,|$)}} int below_zero(const Outer *p, int i) cppverify::pre(p != nullptr && -1 <= i && i < 8) { return p->buf[i]; } -// CHECK-DAG: error: verification failed: below_zero [{{.*}}::bounds@[[@LINE-2]]:10] (counterexample: i [ssa=i_0] [type=i32] = -1, +// CHECK-DAG: :[[@LINE-2]]:10: error: verification failed: below_zero [bounds] +// CHECK-DAG: note: counterexample: {{.*}}i = -1{{( ->|,|$)}} // A postcondition's reads are checked like the body's. int post_past_end(const Ring *r, int i) @@ -222,7 +224,8 @@ int post_past_end(const Ring *r, int i) { return 0; } -// CHECK-DAG: error: verification failed: post_past_end [{{.*}}::bounds@[[@LINE-4]]:50] (counterexample: {{.*}}i [ssa=i_0] [type=i32] = 8, +// CHECK-DAG: :[[@LINE-4]]:50: error: verification failed: post_past_end [bounds] +// CHECK-DAG: note: counterexample: {{.*}}i = 8{{( ->|,|$)}} // grid[i][4] is grid[i + 1][0] in memory, but j indexes a row of 4. int row_overflow(const Outer *p, int i, int j) @@ -230,7 +233,8 @@ int row_overflow(const Outer *p, int i, int j) { return p->grid[i][j]; } -// CHECK-DAG: error: verification failed: row_overflow [{{.*}}::bounds@[[@LINE-2]]:3] (counterexample: i [ssa=i_0] [type=i32] = {{[0-2]}}, j [ssa=j_0] [type=i32] = 4, +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: row_overflow [bounds] +// CHECK-DAG: note: counterexample: {{.*}}i = {{[0-2]}}{{( ->|,|$)}}{{.*}}j = 4{{( ->|,|$)}} void store_past_end(Outer *p, int i) cppverify::pre(p != nullptr && 0 <= i && i <= 8) @@ -238,7 +242,8 @@ void store_past_end(Outer *p, int i) { p->buf[i] = 0; } -// CHECK-DAG: error: verification failed: store_past_end [{{.*}}::bounds@[[@LINE-2]]:13] (counterexample: i [ssa=i_0] [type=i32] = 8, +// CHECK-DAG: :[[@LINE-2]]:13: error: verification failed: store_past_end [bounds] +// CHECK-DAG: note: counterexample: {{.*}}i = 8{{( ->|,|$)}} void slot_past_end(Ring *r, int i) cppverify::pre(r != nullptr && 0 <= i && i <= 8) @@ -247,7 +252,8 @@ void slot_past_end(Ring *r, int i) int &slot = r->buf[i]; slot = 0; } -// CHECK-DAG: error: verification failed: slot_past_end [{{.*}}::bounds@[[@LINE-3]]:3] (counterexample: i [ssa=i_0] [type=i32] = 8, +// CHECK-DAG: :[[@LINE-3]]:3: error: verification failed: slot_past_end [bounds] +// CHECK-DAG: note: counterexample: {{.*}}i = 8{{( ->|,|$)}} void bump_past_end(Ring *r, int i) cppverify::pre(r != nullptr && 0 <= i && i <= 8 && r->head < 100) @@ -255,7 +261,8 @@ void bump_past_end(Ring *r, int i) { bump(r->buf[i]); } -// CHECK-DAG: error: verification failed: bump_past_end [{{.*}}::bounds@[[@LINE-2]]:8] (counterexample: i [ssa=i_0] [type=i32] = 8, +// CHECK-DAG: :[[@LINE-2]]:8: error: verification failed: bump_past_end [bounds] +// CHECK-DAG: note: counterexample: {{.*}}i = 8{{( ->|,|$)}} // A write to buf[i] may be the read of buf[j]. void write_keeps_all(Outer *p, int i, int j) @@ -265,7 +272,8 @@ void write_keeps_all(Outer *p, int i, int j) { p->buf[i] = 7; } -// CHECK-DAG: error: verification failed: write_keeps_all [{{.*}}::postcondition@[[@LINE-4]]:29] (counterexample: i [ssa=i_0] [type=i32] = [[I:[0-7]]], j [ssa=j_0] [type=i32] = [[I]], +// CHECK-DAG: :[[@LINE-4]]:29: error: verification failed: write_keeps_all [postcondition] +// CHECK-DAG: note: counterexample: {{.*}}i = [[I:[0-7]]]{{.*}}j = [[I]]{{( ->|,|$)}} void outside_frame(Outer *p, int i) cppverify::pre(p != nullptr && 0 <= i && i < 8) @@ -273,7 +281,7 @@ void outside_frame(Outer *p, int i) { p->buf[i] = 0; } -// CHECK-DAG: error: verification failed: outside_frame [{{.*}}::frame@[[@LINE-2]]:13] +// CHECK-DAG: :[[@LINE-2]]:13: error: verification failed: outside_frame [frame] void nested_write_wrong(Outer *p) cppverify::pre(p != nullptr) @@ -282,7 +290,7 @@ void nested_write_wrong(Outer *p) { p->inner.y = 3; } -// CHECK-DAG: error: verification failed: nested_write_wrong [{{.*}}::postcondition@[[@LINE-4]]:30] +// CHECK-DAG: :[[@LINE-4]]:30: error: verification failed: nested_write_wrong [postcondition] #else // Arrays in global storage are not modeled; the message names the global. Ring global_ring; From 75e0ed92bf19fe9e21d4ce851dd9f2e87f17cd71 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:08 +0530 Subject: [PATCH 118/259] test: Expect failures as Clang diagnostics in proof_clusters.cpp. --- clang/test/Verify/suite/proof_clusters.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/proof_clusters.cpp b/clang/test/Verify/suite/proof_clusters.cpp index 4ea1b5c8f5..4c0025f31f 100644 --- a/clang/test/Verify/suite/proof_clusters.cpp +++ b/clang/test/Verify/suite/proof_clusters.cpp @@ -72,7 +72,8 @@ cppverify::proof void lie_lemma(int n) { } // CHECK-DAG: error: verification failed: lie_lemma {{.*}}[reason=counterexample] -// CHECK-DAG: error: spec post failed: lie {{.*}}[reason=counterexample] {{.*}}call.lie_lemma +// CHECK-DAG: error: spec post failed: lie {{.*}}[reason=counterexample] +// CHECK-DAG: note: calls lie_lemma( // Without a shared measure, two proofs that rest on each other are a // cycle: the lemma hides the spec, so it uses the spec's postcondition, From 80c53387aab52c939e48da001d9865bd3cd3b05d Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:09 +0530 Subject: [PATCH 119/259] test: Expect failures as Clang diagnostics in proof_steps.cpp. --- clang/test/Verify/suite/proof_steps.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/test/Verify/suite/proof_steps.cpp b/clang/test/Verify/suite/proof_steps.cpp index aae3656a9f..2970a67080 100644 --- a/clang/test/Verify/suite/proof_steps.cpp +++ b/clang/test/Verify/suite/proof_steps.cpp @@ -58,7 +58,7 @@ void wrong_claim(int a, int b) sq_monotone(a, b); } } -// CHECK-DAG: error: verification failed: wrong_claim [{{.*}}::assertion@[[@LINE-4]]:3] +// CHECK-DAG: :[[@LINE-4]]:3: error: verification failed: wrong_claim [assertion] // A lemma's precondition is checked where the proof calls it. void lemma_outside_its_domain(int a, int b) @@ -68,7 +68,7 @@ void lemma_outside_its_domain(int a, int b) sq_monotone(a, b); } } -// CHECK-DAG: error: verification failed: lemma_outside_its_domain [{{.*}}::precondition@[[@LINE-3]]:5] +// CHECK-DAG: :[[@LINE-3]]:5: error: verification failed: lemma_outside_its_domain [precondition] void ghost_local_in_proof(int a) cppverify::pre(0 <= a && a <= 1000) @@ -144,7 +144,7 @@ void wrong_step(int a, int b) sq(a); } } -// CHECK-DAG: error: verification failed: wrong_step [{{.*}}::assertion@[[@LINE-4]]:5] +// CHECK-DAG: :[[@LINE-4]]:5: error: verification failed: wrong_step [assertion] // The chain's steps are local; its conclusion is not. void step_is_local(int a) From 9006035e494774fb8f13f854c1f068a1a06e2c86 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:09 +0530 Subject: [PATCH 120/259] test: Expect failures as Clang diagnostics in range_for.cpp. --- clang/test/Verify/suite/range_for.cpp | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/clang/test/Verify/suite/range_for.cpp b/clang/test/Verify/suite/range_for.cpp index 5a217e247f..43d9ca0f77 100644 --- a/clang/test/Verify/suite/range_for.cpp +++ b/clang/test/Verify/suite/range_for.cpp @@ -37,7 +37,7 @@ int sum3_wrong() s = s + v; return s; } -// CHECK-DAG: error: verification failed: sum3_wrong [{{.*}}::postcondition@{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: sum3_wrong [postcondition]{{.*}}[reason=counterexample] // A reference writes the element. int zeroed() @@ -60,7 +60,7 @@ int zeroed_wrong() x = 0; return a[0]; } -// CHECK-DAG: error: verification failed: zeroed_wrong [{{.*}}::postcondition@{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: zeroed_wrong [postcondition]{{.*}}[reason=counterexample] // An array member through a pointer, with a bound that needs the position. struct Ring { @@ -92,7 +92,7 @@ int total_wrong(const Ring *r) s = s + v; return s; } -// CHECK-DAG: error: verification failed: total_wrong [{{.*}}::postcondition@{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: total_wrong [postcondition]{{.*}}[reason=counterexample] void clear(Ring *r) cv::pre(r != nullptr) @@ -127,7 +127,8 @@ int count_elements_wrong(Ring *r) n = n + 1; return n; } -// CHECK-DAG: error: verification failed: count_elements_wrong [{{.*}}::dereference@[[@LINE-5]]:3{{.*}}r [ssa=r_0] [type=pointer] = 0{{.*}}[reason=counterexample] +// CHECK-DAG: :[[@LINE-5]]:3: error: verification failed: count_elements_wrong [dereference] {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}r = 0{{( ->|,|$)}} // A constant table, break, continue, and a conversion to the variable's // type. @@ -166,7 +167,8 @@ long first_above_wrong(int bound) } return found; } -// CHECK-DAG: error: verification failed: first_above_wrong [{{.*}}bound [ssa=bound_0] [type=i32] = {{[0-9]+}}{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: first_above_wrong {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}bound = {{[0-9]+}}{{( ->|,|$)}} // The elements are read in each iteration; the range is located once. int doubled() @@ -234,7 +236,7 @@ int nested_wrong() s = s + x * y; return s; } -// CHECK-DAG: error: verification failed: nested_wrong [{{.*}}::postcondition@{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: nested_wrong [postcondition]{{.*}}[reason=counterexample] int with_init() cv::post(cv::result == 6) @@ -269,7 +271,7 @@ int letters_wrong() n = n + 1; return n; } -// CHECK-DAG: error: verification failed: letters_wrong [{{.*}}::postcondition@{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: letters_wrong [postcondition]{{.*}}[reason=counterexample] bool any_set() cv::post(cv::result) @@ -293,7 +295,7 @@ bool any_set_wrong() r = r || b; return r; } -// CHECK-DAG: error: verification failed: any_set_wrong [{{.*}}::postcondition@{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: any_set_wrong [postcondition]{{.*}}[reason=counterexample] // An array member of a local record, records bound by reference, and the // user's measure. @@ -344,7 +346,7 @@ int sum_x_wrong() s = s + p.x; return s; } -// CHECK-DAG: error: verification failed: sum_x_wrong [{{.*}}::postcondition@{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: sum_x_wrong [postcondition]{{.*}}[reason=counterexample] int measured() cv::post(true) @@ -368,7 +370,7 @@ int measured_wrong() s = v; return s; } -// CHECK-DAG: error: verification failed: measured_wrong [{{.*}}::termination@{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: measured_wrong [termination]{{.*}}[reason=counterexample] int may_diverge() cv::post(true) From 7451a86a62f3caf88d73569b448b39e60403a7c7 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:10 +0530 Subject: [PATCH 121/259] test: Expect failures as Clang diagnostics in read_instances.cpp. --- clang/test/Verify/suite/read_instances.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/test/Verify/suite/read_instances.cpp b/clang/test/Verify/suite/read_instances.cpp index 8aaa8574cf..98f1a36dff 100644 --- a/clang/test/Verify/suite/read_instances.cpp +++ b/clang/test/Verify/suite/read_instances.cpp @@ -69,7 +69,7 @@ void too_strong(const int *p, int n) { cppverify::check(p[2] >= 1); } -// Z3-DAG: error: verification failed: too_strong [{{.*}}::assertion@[[@LINE-2]]:3] +// Z3-DAG: :[[@LINE-2]]:3: error: verification failed: too_strong [assertion] void outside_range(const int *p, int n) cppverify::pre(valid(p, n + 1) && n >= 3 && n <= 100) @@ -77,11 +77,11 @@ void outside_range(const int *p, int n) { cppverify::check(p[n] >= 0); } -// Z3-DAG: error: verification failed: outside_range [{{.*}}::assertion@[[@LINE-2]]:3] +// Z3-DAG: :[[@LINE-2]]:3: error: verification failed: outside_range [assertion] void wrong_witness(const int *p, int n) cppverify::pre(valid(p, n) && n >= 3 && n <= 100 && p[2] == 7) cppverify::post(cppverify::exists(k, 3, n, p[k] == 7)) { } -// Z3-DAG: error: verification failed: wrong_witness [{{.*}}::postcondition@[[@LINE-3]]:19] +// Z3-DAG: :[[@LINE-3]]:19: error: verification failed: wrong_witness [postcondition] From 7e1ea1931e29ba9561bc5eb04a08a5ac7b732d26 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:10 +0530 Subject: [PATCH 122/259] test: Expect failures as Clang diagnostics in record_references.cpp. --- clang/test/Verify/suite/record_references.cpp | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/clang/test/Verify/suite/record_references.cpp b/clang/test/Verify/suite/record_references.cpp index 0a4eefdf87..e9ff167a3d 100644 --- a/clang/test/Verify/suite/record_references.cpp +++ b/clang/test/Verify/suite/record_references.cpp @@ -128,7 +128,8 @@ void self_frame(Counter &c) { frame(c, c); } -// CHECK-DAG: error: verification failed: self_frame [{{.*}}::aliasing@[[@LINE-2]]:3] (counterexample: c [ssa=c_0] [type=pointer] = +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: self_frame [aliasing] +// CHECK-DAG: note: counterexample: {{.*}}c = void may_alias(Counter &a, Counter &b) cppverify::aliases(a, b) @@ -137,7 +138,7 @@ void may_alias(Counter &a, Counter &b) { a.n = 5; } -// CHECK-DAG: error: verification failed: may_alias [{{.*}}::postcondition@[[@LINE-4]]:23] +// CHECK-DAG: :[[@LINE-4]]:23: error: verification failed: may_alias [postcondition] int sum(const Counter &a, const Counter &b) cppverify::pre(-1000 < a.n && a.n < 1000 && -1000 < b.n && b.n < 1000) @@ -160,21 +161,21 @@ void bad_frame(Counter &c) { c.limit = 3; } -// CHECK-DAG: error: verification failed: bad_frame [{{.*}}::frame@[[@LINE-2]]:11] +// CHECK-DAG: :[[@LINE-2]]:11: error: verification failed: bad_frame [frame] void narrow_caller(Counter &c) cppverify::modifies(c.n) { reset(c); } -// CHECK-DAG: error: verification failed: narrow_caller [{{.*}}::frame@[[@LINE-2]]:3] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: narrow_caller [frame] void narrow_member(Pair &p) cppverify::modifies(p.left.n) { reset(p.left); } -// CHECK-DAG: error: verification failed: narrow_member [{{.*}}::frame@[[@LINE-2]]:3] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: narrow_member [frame] // A callee's whole record is every byte of it, which only a footprint naming // the record, or an object around it, contains; its fields one by one do not. @@ -183,7 +184,7 @@ void fields_one_by_one(Pair &p) { reset(p.left); } -// CHECK-DAG: error: verification failed: fields_one_by_one [{{.*}}::frame@[[@LINE-2]]:3] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: fields_one_by_one [frame] // Array members: indices bounded by their array, and pointers into them // bounded by it. @@ -202,7 +203,7 @@ void put_at(Ring &r, int i, int v) { r.buf[i] = v; } -// CHECK-DAG: error: verification failed: put_at [{{.*}}::bounds@[[@LINE-2]]:12] +// CHECK-DAG: :[[@LINE-2]]:12: error: verification failed: put_at [bounds] void set_first(int *q, int v) cppverify::pre(cppverify::valid(q, 4)) @@ -248,7 +249,7 @@ int past_head(const Ring &r) cppverify::check(h[1] == 0); return 0; } -// CHECK-DAG: error: verification failed: past_head [{{.*}}::bounds@[[@LINE-3]]:3] +// CHECK-DAG: :[[@LINE-3]]:3: error: verification failed: past_head [bounds] // Local references to records bind a place as a parameter does. void local_deref(Counter *p) @@ -279,7 +280,7 @@ void local_wrong_member(Pair *p) Counter &r = p->right; r.n = 0; } -// CHECK-DAG: error: verification failed: local_wrong_member [{{.*}}::frame@[[@LINE-2]]:7] +// CHECK-DAG: :[[@LINE-2]]:7: error: verification failed: local_wrong_member [frame] void local_elements(Counter *a, int n) cppverify::pre(cppverify::valid(a, n) && n >= 0) @@ -304,7 +305,8 @@ void local_past(Counter *a, int i) Counter &r = a[i]; r.n = 3; } -// CHECK-DAG: error: verification failed: local_past [{{.*}}::dereference@[[@LINE-3]]:3] (counterexample: a [ssa=a_0] [type=pointer] = {{[0-9]+}}, i [ssa=i_0] [type=i32] = 4) +// CHECK-DAG: :[[@LINE-3]]:3: error: verification failed: local_past [dereference] +// CHECK-DAG: note: counterexample: a = {{[0-9]+}}, i = 4 // A local record bound to a reference is one object in memory. int local_object() @@ -326,7 +328,7 @@ int local_object_uninitialized() Counter &r = c; return r.limit; } -// CHECK-DAG: error: verification failed: local_object_uninitialized [{{.*}}::initialization@[[@LINE-2]]:3] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: local_object_uninitialized [initialization] // A type invariant holds for a record by value and for one a reference or a // pointer names, at every function boundary. From 8b72a5afc4b25ee59d4b8d6e1a84a7dec443838d Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:11 +0530 Subject: [PATCH 123/259] test: Expect failures as Clang diagnostics in record_values_in_memory.cpp. --- clang/test/Verify/suite/record_values_in_memory.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/record_values_in_memory.cpp b/clang/test/Verify/suite/record_values_in_memory.cpp index 4012f3bb40..64d3f3cfa7 100644 --- a/clang/test/Verify/suite/record_values_in_memory.cpp +++ b/clang/test/Verify/suite/record_values_in_memory.cpp @@ -126,7 +126,7 @@ int past_element(const Bag *b, int k) { return limit_of(b->items[k]); } -// CHECK-DAG: error: verification failed: past_element [{{.*}}::bounds@[[@LINE-2]] +// CHECK-DAG: :[[@LINE-2]]:{{[0-9]+}}: error: verification failed: past_element [bounds] // A copy reads every field, so each must be initialized. struct Pair { @@ -149,4 +149,4 @@ int half_initialized() a = 1; return pair_sum(p); } -// CHECK-DAG: error: verification failed: half_initialized [{{.*}}::initialization@[[@LINE-2]] +// CHECK-DAG: :[[@LINE-2]]:{{[0-9]+}}: error: verification failed: half_initialized [initialization] From 0223e73aa271131b4ca914441241506282ef37c8 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:11 +0530 Subject: [PATCH 124/259] test: Expect failures as Clang diagnostics in region_frames.cpp. --- clang/test/Verify/suite/region_frames.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/clang/test/Verify/suite/region_frames.cpp b/clang/test/Verify/suite/region_frames.cpp index fbfbf259c6..b230a1ad0b 100644 --- a/clang/test/Verify/suite/region_frames.cpp +++ b/clang/test/Verify/suite/region_frames.cpp @@ -47,7 +47,7 @@ void claims_too_much(int *p, int n, int lo) { zero(p + lo, n - lo); } -// CHECK-DAG: error: verification failed: claims_too_much [{{.*}}::initialization@ +// CHECK-DAG: error: verification failed: claims_too_much [initialization] // A function writing a range of its buffer. void zero_from(int *p, int n, int lo) @@ -79,7 +79,7 @@ void writes_outside(int *p, int n, int lo) { p[lo - 1] = 0; } -// CHECK-DAG: error: verification failed: writes_outside [{{.*}}::frame@[[@LINE-2]]:13] +// CHECK-DAG: :[[@LINE-2]]:13: error: verification failed: writes_outside [frame] void range_in_range(int *p, int n) cppverify::pre(valid(p, n) && n >= 4 && n <= 1000) @@ -95,7 +95,7 @@ void range_escapes(int *p, int n) { zero_from(p, n, 1); } -// CHECK-DAG: error: verification failed: range_escapes [{{.*}}::frame@[[@LINE-2]]:3] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: range_escapes [frame] void writes_nothing(int *p, int n) cppverify::pre(valid(p, n) && n >= 1 && n <= 1000) @@ -153,7 +153,7 @@ void changes_sum(int *out, int n) { zero(out, n); } -// CHECK-DAG: error: verification failed: changes_sum [{{.*}}::postcondition@ +// CHECK-DAG: error: verification failed: changes_sum [postcondition] // BMC-DAG: Unresolved: keeps_prefix {{.*}}[reason=callee.contract] // BMC-DAG: error: verification failed: writes_outside From d52b4b6549d3c9856d067ac77c7c68d6d2ce94c5 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:12 +0530 Subject: [PATCH 125/259] test: Expect failures as Clang diagnostics in sequence_encoding_race.test. --- clang/test/Verify/suite/sequence_encoding_race.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/sequence_encoding_race.test b/clang/test/Verify/suite/sequence_encoding_race.test index a656356c78..9842872d44 100644 --- a/clang/test/Verify/suite/sequence_encoding_race.test +++ b/clang/test/Verify/suite/sequence_encoding_race.test @@ -6,4 +6,4 @@ # RUN: %python %S/Inputs/push_chain.py 200 > %t.cpp # RUN: not %cpp-verify --jobs=2 --timeout=10000 %t.cpp -- 2>&1 | FileCheck %s -# CHECK: error: verification failed: chain_bad [{{.*}}::assertion@{{.*}}] (counterexample: {{.*}}) [backend=z3] [reason=counterexample] +# CHECK: error: verification failed: chain_bad [assertion] [backend=z3] [reason=counterexample] From 429a679a934b6b2482c6c055b913b6ba2b223de4 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:12 +0530 Subject: [PATCH 126/259] test: Expect failures as Clang diagnostics in sequence_induction.cpp. --- clang/test/Verify/suite/sequence_induction.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/sequence_induction.cpp b/clang/test/Verify/suite/sequence_induction.cpp index ee84e27f48..6a8740c90e 100644 --- a/clang/test/Verify/suite/sequence_induction.cpp +++ b/clang/test/Verify/suite/sequence_induction.cpp @@ -31,7 +31,7 @@ cppverify::proof void total_concat_wrong(seq s, seq t) if (t.len() > 0) total_concat_wrong(s, t.subrange(0, t.len() - 1)); } -// CHECK-DAG: error: verification failed: total_concat_wrong [{{.*}}::postcondition@[[@LINE-6]]:{{[0-9]+}}] (counterexample: {{.*}}) [backend=z3] [reason=counterexample] +// CHECK-DAG: :[[@LINE-6]]:{{[0-9]+}}: error: verification failed: total_concat_wrong [postcondition] [backend=z3] [reason=counterexample] cppverify::spec int count(seq s, int x) cppverify::decreases(s.len()) From 9f96dc451a57c4ec551f2175858ce89f0249239c Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:13 +0530 Subject: [PATCH 127/259] test: Expect failures as Clang diagnostics in sequences.cpp. --- clang/test/Verify/suite/sequences.cpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/clang/test/Verify/suite/sequences.cpp b/clang/test/Verify/suite/sequences.cpp index 1a008e1b2c..09e3f4fbeb 100644 --- a/clang/test/Verify/suite/sequences.cpp +++ b/clang/test/Verify/suite/sequences.cpp @@ -56,7 +56,8 @@ cppverify::proof void update_wrong(seq s) { cppverify::check(s.update(1, 9)[2] == 9); } -// CHECK-DAG: error: verification failed: update_wrong [{{.*}}::assertion@[[@LINE-2]]:3] (counterexample: s [ssa=s_0] [type=seq] = [{{-?[0-9]+}}, {{-?[0-9]+}}, {{-?[0-9]+}}]) [backend=z3] [reason=counterexample] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: update_wrong [assertion] [backend=z3] [reason=counterexample] +// CHECK-DAG: note: counterexample: s = [{{-?[0-9]+}}, {{-?[0-9]+}}, {{-?[0-9]+}}] cppverify::proof void reverse_small() { @@ -71,7 +72,8 @@ cppverify::proof void reverse_wrong() cppverify::ghost seq s = cppverify::seq_of(1).push(2); cppverify::check(s.reverse()[0] == 1); } -// CHECK-DAG: error: verification failed: reverse_wrong [{{.*}}::assertion@[[@LINE-2]]:3] (counterexample: s [ssa=s_1] [type=seq] = [1, 2]) [backend=z3] [reason=counterexample] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: reverse_wrong [assertion] [backend=z3] [reason=counterexample] +// CHECK-DAG: note: counterexample: s = [1, 2] // reverse states its length; its elements need induction. cppverify::proof void reverse_index(seq s, long long k) @@ -99,7 +101,8 @@ cppverify::proof void elements_differ(seq s) { cppverify::check(s[0] == s[1]); } -// CHECK-DAG: error: verification failed: elements_differ [{{.*}}::assertion@[[@LINE-2]]:3] (counterexample: s [ssa=s_0] [type=seq] = [{{-?[0-9]+}}, {{-?[0-9]+}}]) [backend=z3] [reason=counterexample] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: elements_differ [assertion] [backend=z3] [reason=counterexample] +// CHECK-DAG: note: counterexample: s = [{{-?[0-9]+}}, {{-?[0-9]+}}] // JSON-DAG: "function":"elements_differ"{{.*}}"model":[{"name":"s","sort":"seq","source":{{.*}},"ssa_name":"s_0","value":"[{{-?[0-9]+}}, {{-?[0-9]+}}]"}] // Beyond its length a sequence reads 0, so finitely many indices decide an @@ -109,7 +112,8 @@ cppverify::proof void unbounded_elements(seq s) { cppverify::check(cppverify::forall(k, s[k] >= 0)); } -// CHECK-DAG: error: verification failed: unbounded_elements [{{.*}}::assertion@[[@LINE-2]]:3] (counterexample: s [ssa=s_0] [type=seq] = [{{.*}}-{{[0-9]+.*}}]) [backend=z3] [reason=counterexample] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: unbounded_elements [assertion] [backend=z3] [reason=counterexample] +// CHECK-DAG: note: counterexample: s = [{{.*}}-{{[0-9]+.*}}] cppverify::proof void unbounded_holds(seq s) cppverify::pre(cppverify::forall(k, 0, s.len(), s[k] >= 0)) @@ -136,7 +140,8 @@ cppverify::proof void sum_push_wrong(seq s, int x) cppverify::post(sum(s.push(x)) == sum(s)) { } -// CHECK-DAG: error: verification failed: sum_push_wrong [{{.*}}::postcondition@[[@LINE-3]]:{{[0-9]+}}] (counterexample: {{.*}}x [ssa=x_0] [type=i32] = {{-?[1-9][0-9]*}}) [backend=z3] [reason=counterexample] +// CHECK-DAG: :[[@LINE-3]]:{{[0-9]+}}: error: verification failed: sum_push_wrong [postcondition] [backend=z3] [reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}x = {{-?[1-9][0-9]*}}{{( ->|,|$)}} cppverify::spec bool valid(const int *p, int n) { return true; } @@ -176,7 +181,8 @@ void ghost_loop_wrong(int n) } cppverify::check(s[0] == 1); } -// CHECK-DAG: error: verification failed: ghost_loop_wrong [{{.*}}::assertion@[[@LINE-2]]:3] (counterexample: {{.*}}s [ssa=s_2] [type=seq] = [{{-?[0-9]+}}]{{.*}}) [backend=z3] [reason=counterexample] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: ghost_loop_wrong [assertion] [backend=z3] [reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}s = {{.*}}[{{-?[0-9]+}}] // REPLAY-DAG: Proved obligations: basics (dependencies not checked in replay) // REPLAY-DAG: Proved obligations: reverse_index (dependencies not checked in replay) From 419f0de05a5ec8c60070fe9c0d1858c4cc6c1818 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:13 +0530 Subject: [PATCH 128/259] test: Expect failures as Clang diagnostics in sequences_cvc5.test. --- clang/test/Verify/suite/sequences_cvc5.test | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/clang/test/Verify/suite/sequences_cvc5.test b/clang/test/Verify/suite/sequences_cvc5.test index 8800006c6b..d687f57085 100644 --- a/clang/test/Verify/suite/sequences_cvc5.test +++ b/clang/test/Verify/suite/sequences_cvc5.test @@ -25,7 +25,9 @@ # PORTFOLIO-DAG: Verified: sum_push [backend=portfolio] # PORTFOLIO-DAG: Verified: count_positive [backend=portfolio] # PORTFOLIO-DAG: Verified: reverse_index [backend=portfolio] -# PORTFOLIO-DAG: error: verification failed: reverse_wrong [{{.*}}] (counterexample: s [ssa=s_1] [type=seq] = [1, 2]) [backend=portfolio] [reason=counterexample] -# PORTFOLIO-DAG: error: verification failed: elements_differ [{{.*}}] (counterexample: s [ssa=s_0] [type=seq] = [{{.*}}]) [backend=portfolio] [reason=counterexample] -# PORTFOLIO-DAG: error: verification failed: sum_push_wrong [{{.*}}] (counterexample: {{.*}}) [backend=portfolio] [reason=counterexample] -# PORTFOLIO-DAG: error: verification failed: ghost_loop_wrong [{{.*}}] (counterexample: {{.*}}) [backend=portfolio] [reason=counterexample] +# PORTFOLIO-DAG: error: verification failed: reverse_wrong [{{.*}}] [backend=portfolio] [reason=counterexample] +# PORTFOLIO-DAG: note: counterexample: s = [1, 2] +# PORTFOLIO-DAG: error: verification failed: elements_differ [{{.*}}] [backend=portfolio] [reason=counterexample] +# PORTFOLIO-DAG: note: counterexample: s = [{{.*}}] +# PORTFOLIO-DAG: error: verification failed: sum_push_wrong [{{.*}}] [backend=portfolio] [reason=counterexample] +# PORTFOLIO-DAG: error: verification failed: ghost_loop_wrong [{{.*}}] [backend=portfolio] [reason=counterexample] From 186ba35d3c308d8eefee64db63c0442cc25f2f94 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:14 +0530 Subject: [PATCH 129/259] test: Expect failures as Clang diagnostics in shift_language_mode.cpp. --- clang/test/Verify/suite/shift_language_mode.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/clang/test/Verify/suite/shift_language_mode.cpp b/clang/test/Verify/suite/shift_language_mode.cpp index 19b45a3d71..38ed246338 100644 --- a/clang/test/Verify/suite/shift_language_mode.cpp +++ b/clang/test/Verify/suite/shift_language_mode.cpp @@ -13,7 +13,7 @@ int neg_shift() int m = -1; return m << 1; } -// CXX17-DAG: error: verification failed: neg_shift [{{.*}}::shift@ +// CXX17-DAG: error: verification failed: neg_shift [shift] // CXX20-DAG: Verified: neg_shift [backend=z3] int neg_shift_assign() @@ -23,7 +23,7 @@ int neg_shift_assign() m <<= 2; return m; } -// CXX17-DAG: error: verification failed: neg_shift_assign [{{.*}}::shift@ +// CXX17-DAG: error: verification failed: neg_shift_assign [shift] // CXX20-DAG: Verified: neg_shift_assign [backend=z3] // 2 * 2^31 fits neither int nor unsigned int; modulo 2^32 it is 0. @@ -33,7 +33,7 @@ int past_unsigned(int x) { return x << 31; } -// CXX17-DAG: error: verification failed: past_unsigned [{{.*}}::shift@ +// CXX17-DAG: error: verification failed: past_unsigned [shift] // CXX20-DAG: Verified: past_unsigned [backend=z3] // A contract is C++ too. @@ -43,7 +43,7 @@ int doubled(int x) { return x * 2; } -// CXX17-DAG: error: verification failed: doubled [{{.*}}::shift@ +// CXX17-DAG: error: verification failed: doubled [shift] // CXX20-DAG: Verified: doubled [backend=z3] // 2^31 fits unsigned int, so this is INT_MIN in both. @@ -60,7 +60,7 @@ int too_far(int x, int k) { return x << k; } -// CHECK-DAG: error: verification failed: too_far [{{.*}}::shift@ +// CHECK-DAG: error: verification failed: too_far [shift] int neg_right() cppverify::post(cppverify::result == -2) From 7851e204c21eaff0a6bd5d5dde689ec26166499f Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:14 +0530 Subject: [PATCH 130/259] test: Expect failures as Clang diagnostics in slice_argument_objects.cpp. --- .../test/Verify/suite/slice_argument_objects.cpp | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/clang/test/Verify/suite/slice_argument_objects.cpp b/clang/test/Verify/suite/slice_argument_objects.cpp index 933e3c87af..fbec0b80df 100644 --- a/clang/test/Verify/suite/slice_argument_objects.cpp +++ b/clang/test/Verify/suite/slice_argument_objects.cpp @@ -118,7 +118,8 @@ int copied_past(const int *a) const int *q = a + 2; return first(q, 3); } -// CHECK-DAG: error: verification failed: copied_past [{{.*}}::bounds@[[@LINE-2]]:3] (counterexample: a [ssa=a_0] [type=pointer] = {{[0-9]+}}, q [ssa=q_1] [type=pointer] = {{[0-9]+}}; +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: copied_past [bounds] +// CHECK-DAG: note: counterexample: {{.*}}a = {{[0-9]+}}{{( ->|,|$)}}{{.*}}q = {{[0-9]+}}{{( ->|,|$)}} void copied_write_past(int *a) cppverify::pre(cppverify::valid(a, 4)) @@ -127,7 +128,7 @@ void copied_write_past(int *a) int *q = a + 2; zero2(q, 3); } -// CHECK-DAG: error: verification failed: copied_write_past [{{.*}}::bounds@[[@LINE-2]]:3] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: copied_write_past [bounds] // When c is true, a + 2 has two elements left; b has four. void chosen_past(int *a, int *b, bool c) @@ -137,7 +138,8 @@ void chosen_past(int *a, int *b, bool c) int *q = c ? a + 2 : b; zero2(q, 3); } -// CHECK-DAG: error: verification failed: chosen_past [{{.*}}::bounds@[[@LINE-2]]:3] (counterexample: {{.*}}c [ssa=c_0] [type=bool] = true, +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: chosen_past [bounds] +// CHECK-DAG: note: counterexample: {{.*}}c = true{{( ->|,|$)}} // The callee's contract does not say where its result points. int from_unknown(const int *a) @@ -146,7 +148,7 @@ int from_unknown(const int *a) const int *q = somewhere(a, 4); return first(q, 3); } -// CHECK-DAG: error: verification failed: from_unknown [{{.*}}::bounds@[[@LINE-2]]:3] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: from_unknown [bounds] // The elements must start inside the object too: this result is one element // before a, and the slice would end inside it. @@ -161,7 +163,8 @@ int from_before(const int *a) const int *q = before(a, 4); return first(q, 2); } -// CHECK-DAG: error: verification failed: from_before [{{.*}}::bounds@[[@LINE-2]]:3] (counterexample: a [ssa=a_0] [type=pointer] = {{[0-9]+}}, q [ssa=q_1] [type=pointer] = {{[0-9]+}}; +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: from_before [bounds] +// CHECK-DAG: note: counterexample: {{.*}}a = {{[0-9]+}}{{( ->|,|$)}}{{.*}}q = {{[0-9]+}}{{( ->|,|$)}} // A shorter walk leaves fewer elements than the call needs. int walked_past(const int *a, int n) @@ -178,4 +181,4 @@ int walked_past(const int *a, int n) } return first(q, 2); } -// CHECK-DAG: error: verification failed: walked_past [{{.*}}::bounds@[[@LINE-2]]:3] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: walked_past [bounds] From 530eef894a5cee56d44f9d4921e40de80241bc85 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:15 +0530 Subject: [PATCH 131/259] test: Expect failures as Clang diagnostics in sound_modular_region_frame_fail.cpp. --- clang/test/Verify/suite/sound_modular_region_frame_fail.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/sound_modular_region_frame_fail.cpp b/clang/test/Verify/suite/sound_modular_region_frame_fail.cpp index 568cb506af..2b85a1bf08 100644 --- a/clang/test/Verify/suite/sound_modular_region_frame_fail.cpp +++ b/clang/test/Verify/suite/sound_modular_region_frame_fail.cpp @@ -21,4 +21,4 @@ void invalid_region_frame(int *p) } // VERIFY-DAG: Verified: clobber_offset -// VERIFY-DAG: error: verification failed: invalid_region_frame [{{.*}}::postcondition@ +// VERIFY-DAG: error: verification failed: invalid_region_frame [postcondition] From 93688bff8a03203768d0009a0e8b829b22393229 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:15 +0530 Subject: [PATCH 132/259] test: Expect failures as Clang diagnostics in sound_pointer_stride_fail.cpp. --- clang/test/Verify/suite/sound_pointer_stride_fail.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/sound_pointer_stride_fail.cpp b/clang/test/Verify/suite/sound_pointer_stride_fail.cpp index 781b811cbe..fcd2e360c3 100644 --- a/clang/test/Verify/suite/sound_pointer_stride_fail.cpp +++ b/clang/test/Verify/suite/sound_pointer_stride_fail.cpp @@ -87,4 +87,4 @@ bool past_object_record(const Pair *p, const Pair *q) // VERIFY-DAG: error: verification failed: invalid_adjacent_inequality // VERIFY-DAG: error: verification failed: invalid_char_adjacent_inequality // VERIFY-DAG: error: verification failed: invalid_record_stride -// VERIFY-DAG: error: verification failed: past_object_record [{{.*}}::bounds@ +// VERIFY-DAG: error: verification failed: past_object_record [bounds] From e60a94ff2f67621994f9a93224ee3e794a678206 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:16 +0530 Subject: [PATCH 133/259] test: Expect failures as Clang diagnostics in spec_argument_modes.cpp. --- clang/test/Verify/suite/spec_argument_modes.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/spec_argument_modes.cpp b/clang/test/Verify/suite/spec_argument_modes.cpp index f223750aaa..426ad5b2f8 100644 --- a/clang/test/Verify/suite/spec_argument_modes.cpp +++ b/clang/test/Verify/suite/spec_argument_modes.cpp @@ -23,4 +23,5 @@ cppverify::proof void above_fails(int a) { cppverify::ghost { cppverify::reveal_with_fuel(above, 3); } } -// CHECK-DAG: error: verification failed: above_fails {{.*}}(counterexample: a {{.*}}= 2147483647) [backend=z3] [reason=counterexample] +// CHECK-DAG: error: verification failed: above_fails {{.*}} [backend=z3] [reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}a = 2147483647{{( ->|,|$)}} From 94cd598c19d6748ffc48897b1d31fba0bb588568 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:16 +0530 Subject: [PATCH 134/259] test: Expect failures as Clang diagnostics in spec_automation.cpp. --- clang/test/Verify/suite/spec_automation.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/spec_automation.cpp b/clang/test/Verify/suite/spec_automation.cpp index 303d5a3ac9..e9d212c8f2 100644 --- a/clang/test/Verify/suite/spec_automation.cpp +++ b/clang/test/Verify/suite/spec_automation.cpp @@ -115,9 +115,10 @@ void steps(int n) } // CHECK-DAG: Verified: computed -// CHECK-DAG: verification failed: computed_wrong [{{.*}}::assertion@ +// CHECK-DAG: verification failed: computed_wrong [assertion] // CHECK-DAG: Verified: bounded [backend= -// CHECK-DAG: verification failed: bounded_wrong {{.*}}n [ssa=n_0] [type=i32] = 137 +// CHECK-DAG: verification failed: bounded_wrong +// CHECK-DAG: note: counterexample: {{.*}}n = 137{{( ->|,|$)}} // CHECK-DAG: Verified: inductive // CHECK-DAG: Unresolved: accumulated [backend={{z3|bmc, bound=0}}] [reason=spec.fuel] {{.*}}by induction in a proof function // CHECK-DAG: Verified: accumulate_sum From 1695fe39c8478c96cb16030fb60dd36d615ec01e Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:17 +0530 Subject: [PATCH 135/259] test: Expect failures as Clang diagnostics in spec_fuel_counterexamples.cpp. --- clang/test/Verify/suite/spec_fuel_counterexamples.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/spec_fuel_counterexamples.cpp b/clang/test/Verify/suite/spec_fuel_counterexamples.cpp index 9375de6ad4..2785804e81 100644 --- a/clang/test/Verify/suite/spec_fuel_counterexamples.cpp +++ b/clang/test/Verify/suite/spec_fuel_counterexamples.cpp @@ -50,7 +50,8 @@ void not_inductive(int n) } // CHECK-DAG: Verified: closed_form [ -// CHECK-DAG: error: verification failed: closed_form_wrong [{{.*}}::postcondition@{{.*}}counterexample: {{.*}}n [ssa=n_0] [type=i32] = {{[1-6]}} +// CHECK-DAG: error: verification failed: closed_form_wrong [postcondition] +// CHECK-DAG: note: counterexample: {{.*}}n = {{[1-6]}}{{( ->|,|$)}} // CHECK-DAG: Verified: unbounded [backend=z3] // CHECK-DAG: Unresolved: not_inductive [backend=z3] [reason=spec.fuel] From 2a8476c8c310e24830d0a81f12312ed70be8d7a5 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:17 +0530 Subject: [PATCH 136/259] test: Expect failures as Clang diagnostics in spec_induction.cpp. --- clang/test/Verify/suite/spec_induction.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/spec_induction.cpp b/clang/test/Verify/suite/spec_induction.cpp index 31aea7edcd..d1f0296c75 100644 --- a/clang/test/Verify/suite/spec_induction.cpp +++ b/clang/test/Verify/suite/spec_induction.cpp @@ -47,7 +47,8 @@ cppverify::proof void sum_wrong_once(int n) cppverify::post(2 * sum(n) == n * (n + 1) + (n == 200 ? 1 : 0)) { } -// CHECK-DAG: error: verification failed: sum_wrong_once {{.*}}(counterexample: n [ssa=n_0] [type=i32] = 200) +// CHECK-DAG: error: verification failed: sum_wrong_once {{.*}} +// CHECK-DAG: note: counterexample: n = 200 cppverify::proof void pow2_bounded(int n) cppverify::pre(n >= 0) @@ -71,4 +72,5 @@ cppverify::proof void closed_form_everywhere(int n) cppverify::post(2 * sum(n) == n * (n + 1)) { } -// CHECK-DAG: error: verification failed: closed_form_everywhere {{.*}}(counterexample: n [ssa=n_0] [type=i32] = -{{[0-9]+}}) +// CHECK-DAG: error: verification failed: closed_form_everywhere {{.*}} +// CHECK-DAG: note: counterexample: n = -{{[0-9]+}} From 2ceecd8fe46d11ca668ae3b7cc809e7520784d17 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:18 +0530 Subject: [PATCH 137/259] test: Expect failures as Clang diagnostics in spec_machine_conversion.cpp. --- .../Verify/suite/spec_machine_conversion.cpp | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/clang/test/Verify/suite/spec_machine_conversion.cpp b/clang/test/Verify/suite/spec_machine_conversion.cpp index 93d6f04613..3aa4c2cd28 100644 --- a/clang/test/Verify/suite/spec_machine_conversion.cpp +++ b/clang/test/Verify/suite/spec_machine_conversion.cpp @@ -222,33 +222,33 @@ int contract_division_by_zero(int x, int y) } // VERIFY-DAG: Verified: ghost_in_range -// VERIFY-DAG: error: verification failed: ghost_out_of_range [{{.*}}::overflow@ -// VERIFY-DAG: error: verification failed: ghost_no_wrap [{{.*}}::overflow@ -// VERIFY-DAG: error: verification failed: ghost_negative_unsigned [{{.*}}::overflow@ +// VERIFY-DAG: error: verification failed: ghost_out_of_range [overflow] +// VERIFY-DAG: error: verification failed: ghost_no_wrap [overflow] +// VERIFY-DAG: error: verification failed: ghost_negative_unsigned [overflow] // VERIFY-DAG: Verified: ghost_machine_arithmetic // VERIFY-DAG: Verified: proof_in_range -// VERIFY-DAG: error: verification failed: proof_out_of_range [{{.*}}::overflow@ +// VERIFY-DAG: error: verification failed: proof_out_of_range [overflow] // VERIFY-DAG: Verified: constexpr_argument_in_range -// VERIFY-DAG: error: verification failed: constexpr_argument_out_of_range [{{.*}}::overflow@ +// VERIFY-DAG: error: verification failed: constexpr_argument_out_of_range [overflow] // VERIFY-DAG: Verified: constexpr_short_parameter [ -// VERIFY-DAG: error: verification failed: constexpr_short_parameter_out_of_range [{{.*}}::overflow@ +// VERIFY-DAG: error: verification failed: constexpr_short_parameter_out_of_range [overflow] // VERIFY-DAG: Verified: spec_through_constexpr [ -// VERIFY-DAG: error: verification failed: spec_through_constexpr_out_of_range [{{.*}}::overflow@ +// VERIFY-DAG: error: verification failed: spec_through_constexpr_out_of_range [overflow] // VERIFY-DAG: Verified: contract_exact // VERIFY-DAG: Verified: contract_implicit_widening // VERIFY-DAG: Verified: contract_mixed_arithmetic // VERIFY-DAG: Verified: contract_mixed_widening -// VERIFY-DAG: error: verification failed: contract_mixed_narrowing [{{.*}}::overflow@ +// VERIFY-DAG: error: verification failed: contract_mixed_narrowing [overflow] // VERIFY-DAG: Verified: contract_implicit_unsigned // VERIFY-DAG: Verified: contract_mixed_order // VERIFY-DAG: Verified: contract_conditional // VERIFY-DAG: Verified: contract_explicit_cast [ -// VERIFY-DAG: error: verification failed: contract_explicit_cast_out_of_range [{{.*}}::overflow@ +// VERIFY-DAG: error: verification failed: contract_explicit_cast_out_of_range [overflow] // VERIFY-DAG: Verified: contract_explicit_long -// VERIFY-DAG: error: verification failed: contract_explicit_unsigned_negative [{{.*}}::overflow@ +// VERIFY-DAG: error: verification failed: contract_explicit_unsigned_negative [overflow] // VERIFY-DAG: Verified: contract_shift -// VERIFY-DAG: error: verification failed: contract_bitwise_out_of_range [{{.*}}::overflow@ -// VERIFY-DAG: error: verification failed: contract_division_by_zero [{{.*}}::division-by-zero@ +// VERIFY-DAG: error: verification failed: contract_bitwise_out_of_range [overflow] +// VERIFY-DAG: error: verification failed: contract_division_by_zero [division-by-zero] // Layer 1: the ghost materialization is an explicit conversion. // IR-LABEL: fn ghost_in_range From 5a10f92e7db0bafc4393be3ba5f635fce0925d15 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:18 +0530 Subject: [PATCH 138/259] test: Expect failures as Clang diagnostics in spec_mutual_recursion.cpp. --- clang/test/Verify/suite/spec_mutual_recursion.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/spec_mutual_recursion.cpp b/clang/test/Verify/suite/spec_mutual_recursion.cpp index 21f347cd46..435bf308b5 100644 --- a/clang/test/Verify/suite/spec_mutual_recursion.cpp +++ b/clang/test/Verify/suite/spec_mutual_recursion.cpp @@ -55,7 +55,9 @@ void parity_wrong(int n) // CHECK-DAG: Verified: spec decreases: is_even // CHECK-DAG: Verified: spec decreases: is_odd // CHECK-DAG: Unresolved: spec decreases: ping [reason=spec.termination] (relies on the definition of pong, whose termination is not established) -// CHECK-DAG: error: spec decreases failed: pong {{.*}}[reason=counterexample] (n [type=math-i32] = {{[1-9][0-9]*}}) +// CHECK-DAG: error: spec decreases failed: pong {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}n = {{[1-9][0-9]*}}{{( ->|,|$)}} // CHECK-DAG: Verified: parity // CHECK-DAG: Verified: parity_exclusive -// CHECK-DAG: verification failed: parity_wrong {{.*}}n [ssa=n_0] [type=i32] = {{[0-9]+}} +// CHECK-DAG: verification failed: parity_wrong +// CHECK-DAG: note: counterexample: {{.*}}n = {{[0-9]+}}{{( ->|,|$)}} From 10c7d762db6717218c7e3309373cc919a0cae0ce Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:19 +0530 Subject: [PATCH 139/259] test: Expect failures as Clang diagnostics in spec_post.cpp. --- clang/test/Verify/suite/spec_post.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/spec_post.cpp b/clang/test/Verify/suite/spec_post.cpp index 21dfa9fa96..92c4e5791f 100644 --- a/clang/test/Verify/suite/spec_post.cpp +++ b/clang/test/Verify/suite/spec_post.cpp @@ -77,7 +77,8 @@ cppverify::spec int bad_clamp(int x) { return x > 100 ? 100 : x; } -// CHECK-DAG: error: spec post failed: bad_clamp [backend={{.*}}] [reason=counterexample] (x [type=math-i32] = {{-[0-9]+}}) +// CHECK-DAG: error: spec post failed: bad_clamp [backend={{.*}}] [reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}x = {{-[0-9]+}}{{( ->|,|$)}} void uses_bad_clamp(int x) { @@ -92,6 +93,7 @@ void unfolds_bad_clamp(int x) { cppverify::ghost { cppverify::check(bad_clamp(x) >= 0); } } -// CHECK-DAG: error: verification failed: unfolds_bad_clamp {{.*}}(counterexample: x [ssa=x_0] [type=i32] = {{-[0-9]+}}) +// CHECK-DAG: error: verification failed: unfolds_bad_clamp {{.*}} +// CHECK-DAG: note: counterexample: x = {{-[0-9]+}} // CHECK-DAG: Unresolved: uses_bad_clamp {{.*}}[reason=spec.post] (relies on the postcondition of bad_clamp, which is not established) // JSON-DAG: "function":"uses_bad_clamp"{{.*}}"reason":"spec.post"{{.*}}"status":"unresolved" From 9a97aaf00bca3a95a4abe0f55476f2721233db6c Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:19 +0530 Subject: [PATCH 140/259] test: Expect failures as Clang diagnostics in spec_reads.cpp. --- clang/test/Verify/suite/spec_reads.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/spec_reads.cpp b/clang/test/Verify/suite/spec_reads.cpp index bc6ae82f89..3d159eb2ce 100644 --- a/clang/test/Verify/suite/spec_reads.cpp +++ b/clang/test/Verify/suite/spec_reads.cpp @@ -80,7 +80,7 @@ cppverify::spec int sum_short(const int *p, int n) return sum_short(p, n - 1) + p[n - 1]; } // CHECK-DAG: error: spec reads failed: sum_short {{.*}}[reason=counterexample] -// REPLAY-DAG: verification failed: sum_short.reads [{{.*}}::reads::frame@ +// REPLAY-DAG: verification failed: sum_short.reads [frame] void write_last(int *p, int n) cppverify::pre(n >= 1 && n <= 100 && valid(p, n)) From e38d61cb9cccea521199d619851f1764abae5992 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:20 +0530 Subject: [PATCH 141/259] test: Expect failures as Clang diagnostics in spec_reads_exact.cpp. --- clang/test/Verify/suite/spec_reads_exact.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/spec_reads_exact.cpp b/clang/test/Verify/suite/spec_reads_exact.cpp index da83352a99..3a77a2a558 100644 --- a/clang/test/Verify/suite/spec_reads_exact.cpp +++ b/clang/test/Verify/suite/spec_reads_exact.cpp @@ -70,5 +70,5 @@ unsigned next(const unsigned *p) // CHECK-NEXT: Verified: spec reads: first // CHECK-NEXT: Verified: large_sum // CHECK-NEXT: error: verification failed: negative_sum {{.*}}[reason=counterexample] -// CHECK-NEXT: Verified: smallest_negated +// CHECK: Verified: smallest_negated // CHECK-NEXT: Verified: next [backend=z3]{{$}} From 8475527f08335023b4e63ea55fdff752d871a258 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:20 +0530 Subject: [PATCH 142/259] test: Expect failures as Clang diagnostics in spec_termination.cpp. --- clang/test/Verify/suite/spec_termination.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/clang/test/Verify/suite/spec_termination.cpp b/clang/test/Verify/suite/spec_termination.cpp index 90e97451a5..0fa5fb8b05 100644 --- a/clang/test/Verify/suite/spec_termination.cpp +++ b/clang/test/Verify/suite/spec_termination.cpp @@ -82,15 +82,19 @@ void all_below_small(int n) // CHECK-DAG: Verified: spec decreases: ack // CHECK-DAG: Verified: ack_values -// CHECK-DAG: error: spec decreases failed: diverges_at_one {{.*}}[reason=counterexample] (n [type=math-i32] = 1) +// CHECK-DAG: error: spec decreases failed: diverges_at_one {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}n = 1{{( ->|,|$)}} // CHECK-DAG: Unresolved: uses_divergent [backend={{z3|bmc, bound=[0-9]+}}]{{( \[vacuous\])?}} [reason=spec.termination] (relies on the definition of diverges_at_one, whose termination is not established) // CHECK-DAG: Unresolved: spec decreases unresolved: nested {{.*}}a definition cannot be used to prove its own termination -// CHECK-DAG: error: spec decreases failed: second_unbounded {{.*}}[reason=counterexample] (m [type=math-i32] = {{[1-9][0-9]*}}, n [type=math-i32] = {{-?[0-9]+}}) -// CHECK-DAG: error: spec decreases failed: first_unbounded {{.*}}[reason=counterexample] (m [type=math-i32] = {{-?[0-9]+}}, n [type=math-i32] = {{[1-9][0-9]*}}) +// CHECK-DAG: error: spec decreases failed: second_unbounded {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}m = {{[1-9][0-9]*}}{{( ->|,|$)}}{{.*}}n = {{-?[0-9]+}}{{( ->|,|$)}} +// CHECK-DAG: error: spec decreases failed: first_unbounded {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}m = {{-?[0-9]+}}{{( ->|,|$)}}{{.*}}n = {{[1-9][0-9]*}}{{( ->|,|$)}} // CHECK-DAG: Verified: spec decreases: all_below // CHECK-DAG: Verified: all_below_small -// CHECK-DAG: error: spec decreases failed: reaches_itself {{.*}}[reason=counterexample] (n [type=math-i32] = {{[0-9]+}}) +// CHECK-DAG: error: spec decreases failed: reaches_itself {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}n = {{[0-9]+}}{{( ->|,|$)}} // JSON-DAG: "function":"diverges_at_one"{{.*}}"status":"failed" // JSON-DAG: "function":"ack"{{.*}}"status":"verified" From 2ccfccfac933c8c81a8d1e4ee1ecf311db66d107 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:21 +0530 Subject: [PATCH 143/259] test: Expect failures as Clang diagnostics in spec_when.cpp. --- clang/test/Verify/suite/spec_when.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/spec_when.cpp b/clang/test/Verify/suite/spec_when.cpp index 236f4a5bc1..eccc38ada1 100644 --- a/clang/test/Verify/suite/spec_when.cpp +++ b/clang/test/Verify/suite/spec_when.cpp @@ -77,4 +77,5 @@ cppverify::spec int stalls(int n) { return n <= 1 ? 0 : stalls(n - (n % 2)); } -// CHECK-DAG: error: spec decreases failed: stalls {{.*}}[reason=counterexample] (n [type=math-i32] = {{[0-9]*[02468]}}) +// CHECK-DAG: error: spec decreases failed: stalls {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}n = {{[0-9]*[02468]}}{{( ->|,|$)}} From 9c710c6636813d408cac240837128e0577b20a9d Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:21 +0530 Subject: [PATCH 144/259] test: Expect failures as Clang diagnostics in std_min_max.cpp. --- clang/test/Verify/suite/std_min_max.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/std_min_max.cpp b/clang/test/Verify/suite/std_min_max.cpp index fe13d8e7ec..413d0fb9e1 100644 --- a/clang/test/Verify/suite/std_min_max.cpp +++ b/clang/test/Verify/suite/std_min_max.cpp @@ -42,7 +42,7 @@ int wrong(int a, int b) { return std::min(a, b); } -// CHECK-DAG: error: verification failed: wrong [{{.*}}::postcondition@[[@LINE-4]] +// CHECK-DAG: :[[@LINE-4]]:{{[0-9]+}}: error: verification failed: wrong [postcondition] int clamped(int x) cppverify::post(cppverify::result == std::clamp(x, 0, 9)) From 1ceffdffb9b823f3340eea0fbebe965557c3bdbc Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:21 +0530 Subject: [PATCH 145/259] test: Expect failures as Clang diagnostics in subobject_pointers.cpp. --- .../test/Verify/suite/subobject_pointers.cpp | 36 ++++++++++--------- 1 file changed, 20 insertions(+), 16 deletions(-) diff --git a/clang/test/Verify/suite/subobject_pointers.cpp b/clang/test/Verify/suite/subobject_pointers.cpp index 1f062924ca..c5b6d544ee 100644 --- a/clang/test/Verify/suite/subobject_pointers.cpp +++ b/clang/test/Verify/suite/subobject_pointers.cpp @@ -275,14 +275,15 @@ int pass_too_long(const Ring *r) { return first(r->buf, 9); } -// CHECK-DAG: error: verification failed: pass_too_long [{{.*}}::bounds@[[@LINE-2]]:3#2] (counterexample: r [ssa=r_0] [type=pointer] = {{[0-9]+}} +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: pass_too_long [bounds] +// CHECK-DAG: note: counterexample: {{.*}}r = {{[0-9]+}}{{( ->|,|$)}} int pass_tail_too_long(const Ring *r) cppverify::pre(r != nullptr) { return first(r->buf + 5, 4); } -// CHECK-DAG: error: verification failed: pass_tail_too_long [{{.*}}::bounds@[[@LINE-2]]:3#2] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: pass_tail_too_long [bounds] // The end of buf is a pointer, but get reads the element there: r->head. int pass_end(const Ring *r) @@ -291,7 +292,7 @@ int pass_end(const Ring *r) const int *q = r->buf + 8; return get(q); } -// CHECK-DAG: error: verification failed: pass_end [{{.*}}::bounds@[[@LINE-2]]:3] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: pass_end [bounds] // q[-1] is r->items[3].w, inside *r but before other. int before_member(const Ring *r) @@ -300,7 +301,7 @@ int before_member(const Ring *r) const int *q = r->other; return q[-1]; } -// CHECK-DAG: error: verification failed: before_member [{{.*}}::bounds@[[@LINE-2]]:10#2] +// CHECK-DAG: :[[@LINE-2]]:10: error: verification failed: before_member [bounds] // q[8] is r->head. int local_past(const Ring *r) @@ -309,7 +310,7 @@ int local_past(const Ring *r) const int *q = r->buf; return q[8]; } -// CHECK-DAG: error: verification failed: local_past [{{.*}}::bounds@[[@LINE-2]]:10#2] +// CHECK-DAG: :[[@LINE-2]]:10: error: verification failed: local_past [bounds] int element_past(const Ring *r) cppverify::pre(r != nullptr) @@ -317,7 +318,7 @@ int element_past(const Ring *r) const int *q = &r->buf[2]; return q[6]; } -// CHECK-DAG: error: verification failed: element_past [{{.*}}::bounds@[[@LINE-2]]:10#2] +// CHECK-DAG: :[[@LINE-2]]:10: error: verification failed: element_past [bounds] // q[1] is r->inner.x, next to head. void field_neighbor(Ring *r) @@ -327,7 +328,7 @@ void field_neighbor(Ring *r) int *q = &r->head; q[1] = 0; } -// CHECK-DAG: error: verification failed: field_neighbor [{{.*}}::bounds@[[@LINE-2]]:3#2] +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: field_neighbor [bounds] // q[4] is grid[i + 1][0]. int row_past(const Ring *r, int i) @@ -336,7 +337,7 @@ int row_past(const Ring *r, int i) const int *q = r->grid[i]; return q[4]; } -// CHECK-DAG: error: verification failed: row_past [{{.*}}::bounds@[[@LINE-2]]:10#2] +// CHECK-DAG: :[[@LINE-2]]:10: error: verification failed: row_past [bounds] // it[1] is past items, at r->other. int item_past(const Ring *r) @@ -345,7 +346,7 @@ int item_past(const Ring *r) const Item *it = &r->items[3]; return it[1].v; } -// CHECK-DAG: error: verification failed: item_past [{{.*}}::bounds@[[@LINE-2]]:16#2] +// CHECK-DAG: :[[@LINE-2]]:16: error: verification failed: item_past [bounds] // When c is false, q addresses other, of two elements. int chosen_past(const Ring *r, bool c) @@ -354,7 +355,8 @@ int chosen_past(const Ring *r, bool c) const int *q = c ? r->buf : r->other; return q[2]; } -// CHECK-DAG: error: verification failed: chosen_past [{{.*}}::bounds@[[@LINE-2]]:10] (counterexample: c [ssa=c_0] [type=bool] = false, +// CHECK-DAG: :[[@LINE-2]]:10: error: verification failed: chosen_past [bounds] +// CHECK-DAG: note: counterexample: {{.*}}c = false{{( ->|,|$)}} int walk_past(const Ring *r) cppverify::pre(r != nullptr) @@ -368,7 +370,7 @@ int walk_past(const Ring *r) } return s; } -// CHECK-DAG: error: verification failed: walk_past [{{.*}}::bounds@[[@LINE-4]]:10#2] +// CHECK-DAG: :[[@LINE-4]]:10: error: verification failed: walk_past [bounds] // Forming the address of an element is reading nothing, but the element // must exist: buf[8] does not. @@ -378,7 +380,8 @@ int element_one_past(const Ring *r, int i) const int *q = &r->buf[i]; return 0; } -// CHECK-DAG: error: verification failed: element_one_past [{{.*}}::bounds@[[@LINE-3]]:18] (counterexample: i [ssa=i_0] [type=i32] = 8, +// CHECK-DAG: :[[@LINE-3]]:18: error: verification failed: element_one_past [bounds] +// CHECK-DAG: note: counterexample: {{.*}}i = 8{{( ->|,|$)}} int null_root(const Ring *r) cppverify::post(cppverify::result == 0) @@ -386,7 +389,8 @@ int null_root(const Ring *r) const int *q = r->buf; return 0; } -// CHECK-DAG: error: verification failed: null_root [{{.*}}::dereference@[[@LINE-3]]:18] (counterexample: r [ssa=r_0] [type=pointer] = 0) +// CHECK-DAG: :[[@LINE-3]]:18: error: verification failed: null_root [dereference] +// CHECK-DAG: note: counterexample: r = 0 // Pointers into different members differ by nothing C++ defines. int across_members(const Ring *r) @@ -394,7 +398,7 @@ int across_members(const Ring *r) { return &r->head - r->buf; } -// CHECK-DAG: error: verification failed: across_members [{{.*}}::pointer-difference@[[@LINE-2]]:21] +// CHECK-DAG: :[[@LINE-2]]:21: error: verification failed: across_members [pointer-difference] void write_frame(Ring *r) cppverify::pre(r != nullptr) @@ -403,7 +407,7 @@ void write_frame(Ring *r) int *q = r->other; q[0] = 7; } -// CHECK-DAG: error: verification failed: write_frame [{{.*}}::frame@[[@LINE-2]]:8] +// CHECK-DAG: :[[@LINE-2]]:8: error: verification failed: write_frame [frame] // An operand that `&&`, `||`, or `?:` evaluates only on a path of its own // forms its pointer, and checks it, only there. @@ -436,7 +440,7 @@ void put_past_slot(Ring *r, int i, int v) int *q = i < 4 ? &r->buf[i] : &r->buf[7]; q[1] = v; } -// CHECK-DAG: error: verification failed: put_past_slot [{{.*}}::bounds@[[@LINE-2]]:3 +// CHECK-DAG: :[[@LINE-2]]:3: error: verification failed: put_past_slot [bounds] #else // A pointer that left the function would lose its bounds. struct Holder { From 180609e14b264fa5bece9b0c31fd7924dcadc5d2 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:22 +0530 Subject: [PATCH 146/259] test: Expect failures as Clang diagnostics in switch_statements.cpp. --- clang/test/Verify/suite/switch_statements.cpp | 35 ++++++++++++------- 1 file changed, 23 insertions(+), 12 deletions(-) diff --git a/clang/test/Verify/suite/switch_statements.cpp b/clang/test/Verify/suite/switch_statements.cpp index b22ec47786..783bad1f92 100644 --- a/clang/test/Verify/suite/switch_statements.cpp +++ b/clang/test/Verify/suite/switch_statements.cpp @@ -50,7 +50,8 @@ int fall_wrong(int x) } return r; } -// CHECK-DAG: error: verification failed: fall_wrong [{{.*}}::postcondition@[[@LINE-14]]:{{.*}}x [ssa=x_0] [type=i32] = 0{{[,;]}}{{.*}}[reason=counterexample] +// CHECK-DAG: :[[@LINE-14]]:{{[0-9]+}}: error: verification failed: fall_wrong [postcondition] {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}x = 0{{( ->|,|$)}} // The default label may stand anywhere; it is reached only when no case // matches, and falls through like any other. @@ -90,7 +91,8 @@ int middle_default_wrong(int x) } return r; } -// CHECK-DAG: error: verification failed: middle_default_wrong [{{.*}}x [ssa=x_0] [type=i32] = 6{{[,;]}}{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: middle_default_wrong {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}x = 6{{( ->|,|$)}} // Without a default label, a value no case matches runs nothing. int no_match(int x) @@ -157,7 +159,8 @@ int color_value_wrong(Color c) } return 0; } -// CHECK-DAG: error: verification failed: color_value_wrong [{{.*}}c [ssa=c_0] [type=u32] = 3{{[,;]}}{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: color_value_wrong {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}c = 3{{( ->|,|$)}} // Case values keep the width of the condition. int big_case(long long x) @@ -182,7 +185,8 @@ int big_case_wrong(long long x) return 0; } } -// CHECK-DAG: error: verification failed: big_case_wrong [{{.*}}x [ssa=x_0] [type=i64] = 5000000000{{[,;]}}{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: big_case_wrong {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}x = 5000000000{{( ->|,|$)}} // A GNU case range matches every value from its first to its last. int digit_class(int x) @@ -207,7 +211,8 @@ int digit_class_wrong(int x) return 0; } } -// CHECK-DAG: error: verification failed: digit_class_wrong [{{.*}}x [ssa=x_0] [type=i32] = 9{{[,;]}}{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: digit_class_wrong {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}x = 9{{( ->|,|$)}} // A break in a nested statement leaves the switch; the statements after it // run only where it did not. @@ -246,7 +251,8 @@ int nested_break_wrong(int x, int y) } return r; } -// CHECK-DAG: error: verification failed: nested_break_wrong [{{.*}}x [ssa=x_0] [type=i32] = 1{{[,;]}}{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: nested_break_wrong {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}x = 1{{( ->|,|$)}} // A break in a loop inside a switch leaves the loop; a continue in a switch // inside a loop continues the loop. @@ -406,7 +412,8 @@ int nested_wrong(int a, int b) } return r; } -// CHECK-DAG: error: verification failed: nested_wrong [{{.*}}a [ssa=a_0] [type=i32] = 1{{[,;]}}{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: nested_wrong {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}a = 1{{( ->|,|$)}} // Statements before the first label never run; a declaration there is in // scope after it. @@ -503,7 +510,8 @@ int overflow_in_case(int x) return 0; } } -// CHECK-DAG: error: verification failed: overflow_in_case [{{.*}}::overflow@[[@LINE-5]]:{{.*}}x [ssa=x_0] [type=i32] = 1{{[,;]}}{{.*}}[reason=counterexample] +// CHECK-DAG: :[[@LINE-5]]:{{[0-9]+}}: error: verification failed: overflow_in_case [overflow] {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}x = 1{{( ->|,|$)}} // A spec, a lifted constexpr helper, a proof function, and ghost code may // switch too. @@ -542,7 +550,8 @@ int uses_select_wrong(int x) { return 6; } -// CHECK-DAG: error: verification failed: uses_select_wrong [{{.*}}x [ssa=x_0] [type=i32] = 0{{[,;]}}{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: uses_select_wrong {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}x = 0{{( ->|,|$)}} constexpr int digit_value(char c) { switch (c) { @@ -569,7 +578,8 @@ int uses_digit_value_wrong(char c) { return digit_value(c); } -// CHECK-DAG: error: verification failed: uses_digit_value_wrong [{{.*}}c [ssa=c_0] [type=i8] = 48{{[,;]}}{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: uses_digit_value_wrong {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}c = 48{{( ->|,|$)}} cv::proof int positive_choice(int x) cv::post(cv::result > 0) @@ -620,7 +630,8 @@ int ghosted_wrong(int x) } return x; } -// CHECK-DAG: error: verification failed: ghosted_wrong [{{.*}}x [ssa=x_0] [type=i32] = 3{{[,;]}}{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: ghosted_wrong {{.*}}[reason=counterexample] +// CHECK-DAG: note: counterexample: {{.*}}x = 3{{( ->|,|$)}} // A local lent to a callee ends where a break leaves its block. void set(int *p, int v) @@ -678,7 +689,7 @@ int assumed(int x) [[assume(x > 0)]]; return x; } -// CHECK-DAG: error: verification failed: assumed [{{.*}}::assertion@[[@LINE-3]]:{{.*}}[reason=counterexample] +// CHECK-DAG: :[[@LINE-3]]:{{[0-9]+}}: error: verification failed: assumed [assertion]{{.*}}[reason=counterexample] int lent_directly(int x) cv::post(true) From 2b047e3d2c00d4611dea92127632819e6493df10 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:22 +0530 Subject: [PATCH 147/259] test: Expect failures as Clang diagnostics in trusted_declarations.cpp. --- clang/test/Verify/suite/trusted_declarations.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/trusted_declarations.cpp b/clang/test/Verify/suite/trusted_declarations.cpp index 8440c5a3ce..c19b43b300 100644 --- a/clang/test/Verify/suite/trusted_declarations.cpp +++ b/clang/test/Verify/suite/trusted_declarations.cpp @@ -44,7 +44,8 @@ int uses_above(int x) return above(x); } -// CHECK: trusted_declarations.cpp:13:28: error: verification failed: clamp100 [{{.*}}::postcondition@13:28] (counterexample: {{.*}}result [ssa={{.*}}] [type=i32] = 101 +// CHECK: trusted_declarations.cpp:13:28: error: verification failed: clamp100 [postcondition] +// CHECK: note: counterexample: {{.*}}result = 101{{( ->|,|$)}} // CHECK: Unresolved: scaled [backend=z3] [reason=callee.contract] (relies on the contract of clamp100, which is not established) // CHECK: Trusted: halved (contract assumed, not verified) // CHECK: Trusted: above (contract assumed, not verified) From 5062fec89e4f6da5a8aeaede530b1ed5f706d47f Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:23 +0530 Subject: [PATCH 148/259] test: Expect failures as Clang diagnostics in unbounded_quantifiers.cpp. --- clang/test/Verify/suite/unbounded_quantifiers.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/unbounded_quantifiers.cpp b/clang/test/Verify/suite/unbounded_quantifiers.cpp index 05155a3a0e..d2d7551e16 100644 --- a/clang/test/Verify/suite/unbounded_quantifiers.cpp +++ b/clang/test/Verify/suite/unbounded_quantifiers.cpp @@ -25,7 +25,7 @@ void false_over_integers() { cppverify::check(cppverify::forall(k, 2 * k + 1 > 0)); } -// CHECK-DAG: error: verification failed: false_over_integers [{{.*}}::assertion@{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: false_over_integers [assertion]{{.*}}[reason=counterexample] void true_over_range() { @@ -47,7 +47,7 @@ void cell_claim(int *p) { cppverify::check(cppverify::forall(k, k < 0 || k > 1 || p[k] == 3)); } -// CHECK-DAG: error: verification failed: cell_claim [{{.*}}::assertion@{{.*}}[reason=counterexample] +// CHECK-DAG: error: verification failed: cell_claim [assertion]{{.*}}[reason=counterexample] void cell_claim_holds(int *p) cppverify::pre(valid(p, 4) && p[0] == 3) From 93159eb45275fb0d6674318103a078b267ef47b8 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:23 +0530 Subject: [PATCH 149/259] test: Expect failures as Clang diagnostics in uncontracted_assertions.cpp. --- clang/test/Verify/suite/uncontracted_assertions.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/clang/test/Verify/suite/uncontracted_assertions.cpp b/clang/test/Verify/suite/uncontracted_assertions.cpp index 8345b57c6c..08a38c9b6c 100644 --- a/clang/test/Verify/suite/uncontracted_assertions.cpp +++ b/clang/test/Verify/suite/uncontracted_assertions.cpp @@ -37,7 +37,8 @@ int plain(int n) return n + 1; } -// CHECK-DAG: verification failed: asserts_false [{{.*}}::assertion@ -// CHECK-DAG: verification failed: ghost_false [{{.*}}::assertion@ -// CHECK-DAG: verification failed: asserts_argument [{{.*}}::assertion@{{.*}}n [ssa=n_0] [type=i32] = {{-?[0-9]+}} +// CHECK-DAG: verification failed: asserts_false [assertion] +// CHECK-DAG: verification failed: ghost_false [assertion] +// CHECK-DAG: verification failed: asserts_argument [assertion] +// CHECK-DAG: note: counterexample: {{.*}}n = {{-?[0-9]+}}{{( ->|,|$)}} // CHECK-DAG: Verified: loop_invariant From 92004e8c7a79ad1d84219ad24c5857245bc54076 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:24 +0530 Subject: [PATCH 150/259] test: Expect failures as Clang diagnostics in valid_builtin.cpp. --- clang/test/Verify/suite/valid_builtin.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/valid_builtin.cpp b/clang/test/Verify/suite/valid_builtin.cpp index 7a07662fba..8d61e4a8ef 100644 --- a/clang/test/Verify/suite/valid_builtin.cpp +++ b/clang/test/Verify/suite/valid_builtin.cpp @@ -55,7 +55,7 @@ int past_end(const int *a, int n) { return a[n]; } -// CHECK-DAG: error: verification failed: past_end [{{.*}}::bounds@[[@LINE-2]]:10] +// CHECK-DAG: :[[@LINE-2]]:10: error: verification failed: past_end [bounds] // A user-declared valid works the same way. cppverify::spec bool valid(const long *p, int n) { return true; } From 52693543a4ed15f901074b6def7b46dfeef1cbc5 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:24 +0530 Subject: [PATCH 151/259] test: Expect failures as Clang diagnostics in z3_exec_recursion.cpp. --- clang/test/Verify/suite/z3_exec_recursion.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/z3_exec_recursion.cpp b/clang/test/Verify/suite/z3_exec_recursion.cpp index 06413e94ad..db591966e6 100644 --- a/clang/test/Verify/suite/z3_exec_recursion.cpp +++ b/clang/test/Verify/suite/z3_exec_recursion.cpp @@ -22,7 +22,7 @@ int invalid_nonterminating_exec(int n) } // VERIFY-DAG: Verified: valid_countdown -// VERIFY-DAG: error: verification failed: invalid_nonterminating_exec [{{.*}}::termination@ +// VERIFY-DAG: error: verification failed: invalid_nonterminating_exec [termination] // LOWER-DAG: Lowered: valid_countdown // LOWER-DAG: Lowered: invalid_nonterminating_exec From fde22f5feca6530ca4b57e9ed90122b7c1da2c42 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:25 +0530 Subject: [PATCH 152/259] test: Expect failures as Clang diagnostics in z3_parameter_rebinding.cpp. --- clang/test/Verify/suite/z3_parameter_rebinding.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/z3_parameter_rebinding.cpp b/clang/test/Verify/suite/z3_parameter_rebinding.cpp index 924a393300..f67e990f33 100644 --- a/clang/test/Verify/suite/z3_parameter_rebinding.cpp +++ b/clang/test/Verify/suite/z3_parameter_rebinding.cpp @@ -45,7 +45,8 @@ int relies_on_force_zero(int value) return 0; } -// VERIFY-DAG: error: verification failed: force_zero {{.*}}(counterexample: value [ssa=value_0] [type=i32] = {{-?[1-9][0-9]*}} +// VERIFY-DAG: error: verification failed: force_zero {{.*}} +// VERIFY-DAG: note: counterexample: {{.*}}value = {{-?[1-9][0-9]*}}{{( ->|,|$)}} // VERIFY-DAG: error: verification failed: proof_force_zero // VERIFY-DAG: Verified: doubled // VERIFY-DAG: Verified: valid_after_rebinding From 3e5f1b71be7b20809cd5e210a0a8c2c446aecc5b Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:25 +0530 Subject: [PATCH 153/259] test: Expect failures as Clang diagnostics in z3_references_fail.cpp. --- clang/test/Verify/suite/z3_references_fail.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/z3_references_fail.cpp b/clang/test/Verify/suite/z3_references_fail.cpp index b756d4bf17..ea08e9b704 100644 --- a/clang/test/Verify/suite/z3_references_fail.cpp +++ b/clang/test/Verify/suite/z3_references_fail.cpp @@ -105,5 +105,5 @@ void implicit_effect_in_loop(int &value) // VERIFY-DAG: error: verification failed: alias_without_permission // VERIFY-DAG: error: verification failed: nullable_reference_actual // VERIFY-DAG: error: verification failed: implicit_effect_exceeds_frame -// VERIFY-DAG: error: verification failed: nonterminating_reference_store [{{.*}}::termination@ +// VERIFY-DAG: error: verification failed: nonterminating_reference_store [termination] // VERIFY-DAG: error: verification failed: implicit_effect_in_loop From fe8dda5cc5813b9e6091e724b0f7eb4f959a1279 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:26 +0530 Subject: [PATCH 154/259] test: Expect failures as Clang diagnostics in z3_spec_decreases_sound.cpp. --- clang/test/Verify/suite/z3_spec_decreases_sound.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/z3_spec_decreases_sound.cpp b/clang/test/Verify/suite/z3_spec_decreases_sound.cpp index 8018be74d1..ee8cdc3b56 100644 --- a/clang/test/Verify/suite/z3_spec_decreases_sound.cpp +++ b/clang/test/Verify/suite/z3_spec_decreases_sound.cpp @@ -49,4 +49,4 @@ cppverify::proof void nonterminating_proof(int n) // VERIFY-DAG: Verified: spec decreases: terminating_after_branch // VERIFY-DAG: error: spec decreases failed: nonterminating_descent // VERIFY-DAG: error: spec decreases failed: nonterminating_after_branch -// VERIFY-DAG: error: verification failed: nonterminating_proof [{{.*}}::termination@ +// VERIFY-DAG: error: verification failed: nonterminating_proof [termination] From 475ccf3d59d8a281b5921162138773c645f361c0 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:26 +0530 Subject: [PATCH 155/259] test: Expect failures as Clang diagnostics in z3_undefined_behavior.cpp. --- clang/test/Verify/suite/z3_undefined_behavior.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/z3_undefined_behavior.cpp b/clang/test/Verify/suite/z3_undefined_behavior.cpp index cad4c1566e..12ba85f388 100644 --- a/clang/test/Verify/suite/z3_undefined_behavior.cpp +++ b/clang/test/Verify/suite/z3_undefined_behavior.cpp @@ -172,7 +172,7 @@ int unsafe_min_remainder(int x) // VERIFY-DAG: error: verification failed: unsafe_overflow_after_spec_result // VERIFY-DAG: error: verification failed: unsafe_overflow_after_spec_initialization // VERIFY-DAG: error: verification failed: unsafe_overflow_after_spec_assignment -// VERIFY-DAG: error: verification failed: invalid_out_of_range_spec_result [{{.*}}::overflow@ +// VERIFY-DAG: error: verification failed: invalid_out_of_range_spec_result [overflow] // VERIFY-DAG: error: verification failed: unsafe_signed_subtract // VERIFY-DAG: error: verification failed: unsafe_signed_multiply // VERIFY-DAG: error: verification failed: unsafe_signed_negation From d7fb413ee2de69a4735dd32001d83713ea02f890 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:27 +0530 Subject: [PATCH 156/259] docs: Show failures as Clang diagnostics in chapter 7. --- .../book/part-i/ch07-memory-aliasing-frames.rst | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/website/source/book/part-i/ch07-memory-aliasing-frames.rst b/website/source/book/part-i/ch07-memory-aliasing-frames.rst index fe85fe7e50..4956451e55 100644 --- a/website/source/book/part-i/ch07-memory-aliasing-frames.rst +++ b/website/source/book/part-i/ch07-memory-aliasing-frames.rst @@ -79,7 +79,19 @@ same. The swap by sums is not: .. code-block:: text - sums.cpp:6:30: error: verification failed: swap_by_sums [...] (counterexample: a [ssa=a_0] [type=pointer] = 1, b [ssa=b_0] [type=pointer] = 1; ...) + sums.cpp:6:30: error: verification failed: swap_by_sums [postcondition] [backend=z3] [reason=counterexample] + 6 | cv::post(*a == cv::old(*b) && *b == cv::old(*a)) + | ~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~ + sums.cpp:6:30: note: counterexample: a = 1, b = 1 + sums.cpp:8:6: note: stores 2000 at address 1 + 8 | *a = *a + *b; *b = *a - *b; *a = *a - *b; + | ^ + sums.cpp:8:20: note: stores 0 at address 1 + 8 | *a = *a + *b; *b = *a - *b; *a = *a - *b; + | ^ + sums.cpp:8:34: note: stores 0 at address 1 + 8 | *a = *a + *b; *b = *a - *b; *a = *a - *b; + | ^ With ``a == b`` the first statement doubles the value and the second sets it to 0. From c395c696ad453c03b1e749fccece7699a7fbfb29 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:27 +0530 Subject: [PATCH 157/259] docs: Show failures as Clang diagnostics in chapter 13. --- .../part-ii/ch13-spec-and-proof-functions.rst | 40 ++++++++++++++----- 1 file changed, 31 insertions(+), 9 deletions(-) diff --git a/website/source/book/part-ii/ch13-spec-and-proof-functions.rst b/website/source/book/part-ii/ch13-spec-and-proof-functions.rst index 57033d1c10..0aa1950b17 100644 --- a/website/source/book/part-ii/ch13-spec-and-proof-functions.rst +++ b/website/source/book/part-ii/ch13-spec-and-proof-functions.rst @@ -180,7 +180,10 @@ is checked like any other: .. code-block:: text - stuck.cpp:4:42: error: spec decreases failed: stuck [backend=z3] [reason=counterexample] (n [type=math-i32] = 1) + stuck.cpp:4:42: error: spec decreases failed: stuck [backend=z3] [reason=counterexample] + 4 | return n <= 0 ? 0 : cv::choose(k, k == stuck(n) + 1); + | ^ + stuck.cpp:4:42: note: counterexample: n = 1 Unresolved: forty_two [backend=z3] [reason=spec.termination] (relies on the definition of stuck, whose termination is not established) At ``n = 1`` the definition says that ``stuck(1)`` equals ``stuck(1) + 1``, a @@ -547,7 +550,10 @@ solver proves it, the counterexample is confirmed: .. code-block:: text - error: verification failed: small_power [...::postcondition@...] (counterexample: n [ssa=n_0] [type=i32] = 1000023594; confirmed by a proof at this input, since its check could not compute pow2(1000023594)) [backend=z3] [reason=counterexample] + example.cpp:11:20: error: verification failed: small_power [postcondition] (confirmed by a proof at this input, since its check could not compute pow2(1000023594)) [backend=z3] [reason=counterexample] + 11 | cv::post(pow2(n) < 1000) + | ~~~~~~~~^~~~~~ + example.cpp:11:20: note: counterexample: n = 1000023594 The failure rests on the facts the proof used (here ``pow2``'s postcondition); if one of them is not established, the verdict is not a @@ -616,7 +622,10 @@ Which to do depends on what you believe: .. code-block:: text Verified: fibo_at_least_5 [backend=z3] - error: verification failed: fibo_small [...::postcondition@...] (counterexample: n [ssa=n_0] [type=i32] = 1000000000; confirmed by a proof at this input that uses the contract of fibo_at_least_5, since its check could not compute fibo(1000000000)) [backend=z3] [reason=counterexample] + example.cpp:21:20: error: verification failed: fibo_small [postcondition] (confirmed by a proof at this input that uses the contract of fibo_at_least_5, since its check could not compute fibo(1000000000)) [backend=z3] [reason=counterexample] + 21 | cv::post(fibo(n) < 5) + | ~~~~~~~~^~~ + example.cpp:21:20: note: counterexample: n = 1000000000 The proof instantiates a lemma where its postcondition speaks of the same spec application as the claim, here ``fibo_at_least_5`` at @@ -661,7 +670,10 @@ those assumptions. A lemma over memory is used the same way: .. code-block:: text Verified: total_nonneg [backend=z3] - error: verification failed: total_negative [...::postcondition@...] (counterexample: n [ssa=n_0] [type=i32] = 1000000000, a [ssa=a_0] [type=pointer] = 1; confirmed by a proof at this input that uses the contract of total_nonneg, since its check could not compute total(1, 1000000000)) [backend=z3] [reason=counterexample] + example.cpp:20:24: error: verification failed: total_negative [postcondition] (confirmed by a proof at this input that uses the contract of total_nonneg, since its check could not compute total(1, 1000000000)) [backend=z3] [reason=counterexample] + 20 | cv::post(total(a, n) < 0) + | ~~~~~~~~~~~~^~~ + example.cpp:20:24: note: counterexample: a = 1, n = 1000000000 Only contracts that are established count: a confirmation runs after every function is verified, and a lemma that failed, or that rests on a fact that @@ -999,8 +1011,17 @@ it means the same: .. code-block:: text - choose.cpp:5:43: error: verification failed: write_inside [...] (counterexample: a [ssa=a_0] [type=pointer] = ..., n [ssa=n_0] [type=i32] = 1, ...) - choose.cpp:12:33: error: verification failed: written_differently [...] (counterexample: n [ssa=n_0] [type=i32] = ) + choose.cpp:4:43: error: verification failed: write_inside [postcondition] [backend=z3] [reason=counterexample] + 4 | cv::post(cv::choose(k, 0, n, a[k] == x) == + | ^ + choose.cpp:4:43: note: counterexample: a = 8856, n = 1, x = -1 + choose.cpp:7:8: note: stores 0 at address 8856 + 7 | a[0] = x == 0 ? 1 : 0; + | ^ + choose.cpp:11:33: error: verification failed: written_differently [postcondition] [backend=z3] [reason=counterexample] + 11 | cv::post(cv::choose(k, k > n) == cv::choose(k, n < k)) + | ~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~ + choose.cpp:11:33: note: counterexample: n = In every counterexample to ``write_inside`` the write changes ``a[0]``, a cell the condition reads, so the choice may move. When a proof needs equivalent conditions to choose alike, write @@ -1174,9 +1195,10 @@ where a finite derivation shows it. Verified: spec post: reach Verified: three_reaches_twelve [backend=z3] Verified: no_way_back [backend=z3] - book.cpp:25:14: error: verification failed: wrong_way [...::postcondition@25:14] - (counterexample: a [ssa=a_0] [type=i32] = 38, b [ssa=b_0] [type=i32] = 38) - [backend=z3] [reason=counterexample] + book.cpp:25:14: error: verification failed: wrong_way [postcondition] [backend=z3] [reason=counterexample] + 25 | cv::post(a < b) + | ~~^~~ + book.cpp:25:14: note: counterexample: a = 38, b = 38 A proof sees ``reach`` through its body, unfolded once at each application it names: ``reach(6, 12)`` holds by the edge ``6 -> 12`` and ``reach(12, 12)``, From 7bce66fedc7980b2c1bb3389657f741a05f5df29 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:28 +0530 Subject: [PATCH 158/259] docs: Show failures as Clang diagnostics in chapter 14. --- .../part-ii/ch14-pointers-frames-modifies.rst | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/website/source/book/part-ii/ch14-pointers-frames-modifies.rst b/website/source/book/part-ii/ch14-pointers-frames-modifies.rst index 4acdea77d3..0c37e03c47 100644 --- a/website/source/book/part-ii/ch14-pointers-frames-modifies.rst +++ b/website/source/book/part-ii/ch14-pointers-frames-modifies.rst @@ -319,7 +319,10 @@ and footprints name it, and the same frame reasoning as for a buffer applies: Verified: push [backend=z3] Verified: clear [backend=z3] - stack.cpp:36:21: error: verification failed: push_full [...::bounds@36:21] (counterexample: s [ssa=s_0] [type=pointer] = 1; trace: heap-write.store@36:21 address=65 value=) [backend=z3] [reason=counterexample] + stack.cpp:36:21: error: verification failed: push_full [bounds] [backend=z3] [reason=counterexample] + 36 | s->items[s->size] = v; + | ^ + stack.cpp:36:21: note: counterexample: s = 1 ``push`` writes exactly two cells, so its postcondition can promise that every item below the old size is unchanged. ``clear`` writes a range of the member @@ -379,7 +382,16 @@ that runs one element too far reads ``s->size`` and fails: .. code-block:: text Verified: count_zero [backend=z3] - stack.cpp:31:10: error: verification failed: count_past [...::bounds@31:10#2] (counterexample: n [ssa=n_1] [type=i32] = 0, n [ssa=n_2] [type=i32] = 0, q [ssa=q_1] [type=pointer] = 1, q [ssa=q_2] [type=pointer] = 65, s [ssa=s_0] [type=pointer] = 1; trace: loop.entry@26:3 -> loop.inductive iteration@26:3 condition=true) [backend=z3] [reason=counterexample] + stack.cpp:31:10: error: verification failed: count_past [bounds] [backend=z3] [reason=counterexample] + 31 | if (*q == 0) + | ^ + stack.cpp:31:10: note: counterexample: s = 1, n = 0, q = 1 -> 65 + stack.cpp:26:3: note: enters the loop + 26 | for (const int *q = s->items; q != s->items + s->size + 1; q = q + 1) + | ^ + stack.cpp:26:3: note: starts an arbitrary iteration of the loop, where its condition is true + note: the counterexample's state at the loop at 26:3 is any state its invariants allow, not necessarily one an execution reaches + note: no execution fails this check within 10 iterations of each loop In ``count_past`` the solver chooses a full stack, and ``q`` reaches 65, the address of ``s->size`` with ``s`` at 1. The verifier itself states that a From a3c3169116eaee9c531a0b2a984047de3f234ea3 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:28 +0530 Subject: [PATCH 159/259] docs: Show failures as Clang diagnostics in chapter 18. --- .../book/part-ii/ch18-undefined-behavior.rst | 27 ++++++++++++++----- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/website/source/book/part-ii/ch18-undefined-behavior.rst b/website/source/book/part-ii/ch18-undefined-behavior.rst index b15fe689ab..b811591e5f 100644 --- a/website/source/book/part-ii/ch18-undefined-behavior.rst +++ b/website/source/book/part-ii/ch18-undefined-behavior.rst @@ -102,8 +102,10 @@ The classic example — the tool tells you the precondition you forgot: .. code-block:: text - abs.cpp:2:3: error: verification failed: abs_unguarded [...::overflow@2:3] - (counterexample: x [type=i32] = -2147483648) + abs.cpp:2:3: error: verification failed: abs_unguarded [overflow] [backend=z3] [reason=counterexample] + 2 | { return x < 0 ? -x : x; } + | ^ + abs.cpp:2:3: note: counterexample: x = -2147483648 Verified: abs_guarded [backend=z3] Negating ``INT_MIN`` overflows, so the first version fails at that input; @@ -135,8 +137,10 @@ base is ``p`` then carries the obligation ``0 <= i < n``: .. code-block:: text Verified: get [backend=z3] - error: verification failed: last [...::bounds@11:10] (counterexample: - n = 1, p = 1) + example.cpp:10:10: error: verification failed: last [bounds] [backend=z3] [reason=counterexample] + 10 | { return p[n]; } // FAILS: p[n] is one past the end + | ^ + example.cpp:10:10: note: counterexample: p = 1, n = 1 ```` declares ``valid`` for every pointee type, so the same marker describes an ``int`` buffer, a ``char`` buffer, or an array of @@ -287,8 +291,10 @@ very input it means to exclude: .. code-block:: text - per.cpp:2:17: error: verification failed: contract of per_item - [...::contract::division-by-zero@2:17] (counterexample: items [type=i32] = 0) + per.cpp:2:17: error: verification failed: contract of per_item [division-by-zero] [backend=z3] [reason=counterexample] + 2 | cv::pre(total / items <= 100 && items > 0) + | ^ + per.cpp:2:17: note: counterexample: items = 0 Verified: per_item [backend=z3] The body verifies, since its proof assumes the precondition. The contract does @@ -325,7 +331,14 @@ therefore holds, and an assert documents a fact the proof checks. With .. code-block:: text - ratio.cpp:7:3: error: verification failed: ratio [...::unreachable@7:3] (counterexample: parts [ssa=parts_0] [type=i32] = 0, ...) [backend=z3] [reason=counterexample] + ratio.cpp:7:3: error: verification failed: ratio [unreachable] [backend=z3] [reason=counterexample] + 7 | assert(parts > 0 && "parts must be positive"); + | ^ + /usr/include/assert.h:105:9: note: expanded from macro 'assert' + 105 | : __assert_fail (#expr, __ASSERT_FILE, __ASSERT_LINE, \ + | ^ + ratio.cpp:7:3: note: counterexample: total = 0, parts = 0 + ratio.cpp:7:3: note: takes the false branch The division needs ``parts != 0``, which the assert establishes, and the assert can fail: a caller may pass ``parts == 0``. Adding From 980703c6050a463b73da19d6b0f3d3d61baee9ec Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:29 +0530 Subject: [PATCH 160/259] docs: Show failures as Clang diagnostics in chapter 20. --- .../book/part-ii/ch20-mathematics-to-code.rst | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/website/source/book/part-ii/ch20-mathematics-to-code.rst b/website/source/book/part-ii/ch20-mathematics-to-code.rst index e51f7347a3..a3adc2f9d6 100644 --- a/website/source/book/part-ii/ch20-mathematics-to-code.rst +++ b/website/source/book/part-ii/ch20-mathematics-to-code.rst @@ -253,10 +253,14 @@ Both are reported with the input that shows it: .. code-block:: text - error: verification failed: clamp_overlap [...::assertion@10:3] - (counterexample: hi = 0, lo = 0, x = 0) - error: verification failed: clamp_gap [...::assertion@27:3] - (counterexample: hi = 0, lo = 0, x = 0) + example.cpp:10:3: error: verification failed: clamp_overlap [assertion] [backend=z3] [reason=counterexample] + 10 | cv::disjoint_behaviors + | ^ + example.cpp:10:3: note: counterexample: x = 0, lo = 0, hi = 0 + example.cpp:27:3: error: verification failed: clamp_gap [assertion] [backend=z3] [reason=counterexample] + 27 | cv::complete_behaviors + | ^ + example.cpp:27:3: note: counterexample: x = 0, lo = 0, hi = 0 Universal statements: sorted arrays ----------------------------------- @@ -434,8 +438,14 @@ fails: .. code-block:: text - error: verification failed: which [...::postcondition@3:15] - (counterexample: result = 0, a = 536, n = 2; trace: call.argmax ...) + example.cpp:3:23: error: verification failed: which [postcondition] [backend=z3] [reason=counterexample] + 3 | cv::post(cv::result == some_max(a, n)) + | ~~~~~~~~~~~^~~~~~~~~~~~~~~~~ + example.cpp:3:23: note: counterexample: a = 536, n = 2, result = 0 + example.cpp:5:3: note: calls argmax(536, 2) + 5 | return argmax(a, n); + | ^ + example.cpp:5:3: note: returns 0 In the counterexample both elements are maxima, ``argmax`` returns 0, and ``cppverify::choose`` picks 1. From bbc567cc03f35555616c0a183fe2e2dce7f105a8 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:29 +0530 Subject: [PATCH 161/259] docs: Show failures as Clang diagnostics in the binary search case study. --- website/source/case-studies/binary-search.rst | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/website/source/case-studies/binary-search.rst b/website/source/case-studies/binary-search.rst index 9860d81ee6..b9440560ea 100644 --- a/website/source/case-studies/binary-search.rst +++ b/website/source/case-studies/binary-search.rst @@ -30,14 +30,26 @@ is always on, so the encoder generates the obligation itself and it fails: .. code-block:: text - error: verification failed: bsearch_broken [...::overflow@...] - (counterexample: lo = 1073741824, hi = 1073741824) - -Those two values sum to 2,147,483,648, which is ``INT_MAX + 1``. The verifier -did not merely report that something might overflow; it named the check that -fails and produced the concrete state that breaks it. The solver chooses the -witness, so another version may report a different pair with the same -overflow. + binary_search.cpp:28:5: error: verification failed: bsearch_broken [overflow] [backend=z3] [reason=counterexample] + 28 | int mid = (lo + hi) / 2; + | ^ + binary_search.cpp:28:5: note: counterexample: a = 1, n = 1073741825, lo = 0 -> 1073741824, hi = 1073741824, res = -1 -> 1073741824 + binary_search.cpp:24:3: note: enters the loop + 24 | while (lo <= hi) + | ^ + binary_search.cpp:24:3: note: starts an arbitrary iteration of the loop, where its condition is true + note: the counterexample's state at the loop at 24:3 is any state its invariants allow, not necessarily one an execution reaches + note: an execution fails this check within 2 iterations of each loop (counterexample: a = 1, n = 2147483647, key = -2147483647, lo = 0 -> 1073741824, hi = 2147483646, res = -1, mid = 1073741823) + +In the iteration the counterexample starts, ``lo`` and ``hi`` are both +1073741824, which sum to 2,147,483,648, ``INT_MAX + 1``. That state comes from +the loop's invariant, so the verifier then unrolls the loop and finds an +execution that gets there: in an array of ``INT_MAX`` elements, the first +midpoint is 1073741823, the key is larger, and the second iteration adds +1073741824 and 2147483646. The verifier did not merely report that something +might overflow; it named the check that fails and produced the concrete state +that breaks it. The solver chooses the witness, so another version may report +a different pair with the same overflow. Replacing the midpoint with the standard safe form makes the same function verify: From 01456573fce584cc96c262b4cea7d3ea10ab211d Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:30 +0530 Subject: [PATCH 162/259] docs: Show failures as Clang diagnostics in the ghost, spec, and proofs reference. --- website/source/language/ghost-proofs.rst | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/website/source/language/ghost-proofs.rst b/website/source/language/ghost-proofs.rst index 260db63f3a..8e81cadbd1 100644 --- a/website/source/language/ghost-proofs.rst +++ b/website/source/language/ghost-proofs.rst @@ -171,7 +171,10 @@ integer, and adding to it never wraps. .. code-block:: text Verified: large [backend=z3] - reads.cpp:13:24: error: verification failed: wraps [...::postcondition@13:24] (counterexample: ...) [backend=z3] [reason=counterexample] + reads.cpp:13:24: error: verification failed: wraps [postcondition] [backend=z3] [reason=counterexample] + 13 | cv::post(pair_sum(p) < 0) + | ~~~~~~~~~~~~^~~ + reads.cpp:13:24: note: counterexample: p = -1 Before 0.2, a value read in a spec body kept its machine type, so the sum above wrapped to a negative ``int``: ``wraps`` verified, and ``large`` could @@ -284,7 +287,10 @@ among ``a[0]`` to ``a[n - 1]``, inside its frame; ``index_past`` also reads .. code-block:: text Verified: spec reads: index_of - reads.cpp:10:34: error: spec reads failed: index_past [backend=z3] [reason=counterexample] (a [type=pointer] = 0, n [type=math-i32] = 0) + reads.cpp:10:34: error: spec reads failed: index_past [backend=z3] [reason=counterexample] + 10 | return cv::choose(k, 0, n + 1, a[k] == x); + | ^ + reads.cpp:10:34: note: counterexample: a = 0, n = 0 The counterexample is the empty buffer: with ``n = 0``, ``index_past`` reads ``a[0]``, and ``cppverify::reads(a, 0)`` declares no cell. From 52f9e5c7eca63cb3b43afcb50874f309cab49193 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:30 +0530 Subject: [PATCH 163/259] docs: Show failures as Clang diagnostics in the integers reference. --- website/source/language/integers.rst | 33 ++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/website/source/language/integers.rst b/website/source/language/integers.rst index f68dad1eae..cde4303c9c 100644 --- a/website/source/language/integers.rst +++ b/website/source/language/integers.rst @@ -130,12 +130,19 @@ contract that means the wrapped value says so with ``% 2^N``. .. code-block:: text - abs.cpp:2:3: error: verification failed: abs_unguarded [...::overflow@2:3] - (counterexample: x [type=i32] = -2147483648) + abs.cpp:2:3: error: verification failed: abs_unguarded [overflow] [backend=z3] [reason=counterexample] + 2 | { return x < 0 ? -x : x; } + | ^ + abs.cpp:2:3: note: counterexample: x = -2147483648 Verified: abs_guarded [backend=z3] Verified: mix [backend=z3] - abs.cpp:10:64: error: verification failed: mix_wrong [...::postcondition@10:64] - (counterexample: result [type=u32] = 0, a [type=u32] = 1, ...) + abs.cpp:10:64: error: verification failed: mix_wrong [postcondition] [backend=z3] [reason=counterexample] + 10 | unsigned mix_wrong(unsigned a, unsigned b) cv::post(cv::result == a + b) + | ~~~~~~~~~~~^~~~~~~~ + abs.cpp:10:64: note: counterexample: a = 1, b = 4294967295, result = 0 + abs.cpp:11:3: note: returns 0 + 11 | { return a + b; } + | ^ Negating ``INT_MIN`` overflows, so ``abs_unguarded`` fails at the overflow check with that input, and the precondition the tool asks for makes @@ -194,7 +201,10 @@ shift is undefined, and the verifier finds the input: .. code-block:: text - shift.cpp:5:3: error: verification failed: doubled [...::shift@5:3] (counterexample: x [ssa=x_0] [type=i32] = -1; trace: return.return@5:3 value=-2) [backend=z3] [reason=counterexample] + shift.cpp:5:3: error: verification failed: doubled [shift] [backend=z3] [reason=counterexample] + 5 | return x << 1; + | ^ + shift.cpp:5:3: note: counterexample: x = -1 Compiled as C++20, with ``cpp-verify shift.cpp -- -std=c++20``, the same function verifies: @@ -302,7 +312,10 @@ of range, so the conversion is an ``overflow`` obligation: Verified: code [backend=z3] Verified: from_code [backend=z3] - colors.cpp:18:3: error: verification failed: unchecked [...::overflow@18:3] (counterexample: v [ssa=v_0] [type=i32] = -1; ...) [backend=z3] [reason=counterexample] + colors.cpp:18:3: error: verification failed: unchecked [overflow] [backend=z3] [reason=counterexample] + 18 | return static_cast(v); + | ^ + colors.cpp:18:3: note: counterexample: v = -1 ``code`` may return ``3``: no enumerator has that value, but ``Color`` does. With a fixed underlying type, every value of that type is possible: @@ -321,7 +334,13 @@ With a fixed underlying type, every value of that type is possible: .. code-block:: text - levels.cpp:4:28: error: verification failed: level [...::postcondition@4:28] (counterexample: result [ssa=__result_1] [type=i32] = 3, l [ssa=l_0] [type=u8] = 3; ...) [backend=z3] [reason=counterexample] + levels.cpp:4:28: error: verification failed: level [postcondition] [backend=z3] [reason=counterexample] + 4 | cv::post(0 <= cv::result && cv::result <= 2) + | ~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~ + levels.cpp:4:28: note: counterexample: l = 3, result = 3 + levels.cpp:6:3: note: returns 3 + 6 | return static_cast(l); + | ^ The range is a fact about machine values. In a ``cv::spec``, a parameter of an enumeration type is a mathematical integer like any other, so a spec's claim From 8fef2799ea736b7b26e4550278063cc4809f7dd2 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:31 +0530 Subject: [PATCH 164/259] docs: Show failures as Clang diagnostics in the pointers reference. --- website/source/language/pointers.rst | 50 +++++++++++++++++++++++----- 1 file changed, 42 insertions(+), 8 deletions(-) diff --git a/website/source/language/pointers.rst b/website/source/language/pointers.rst index 77d3685988..dffe2dc817 100644 --- a/website/source/language/pointers.rst +++ b/website/source/language/pointers.rst @@ -173,10 +173,24 @@ since the callee may read it first. Verified: copy_to [backend=z3] Verified: seven [backend=z3] Verified: five_or_zero [backend=z3] - out.cpp:48:3: error: verification failed: read_after_miss [...::initialization@48:3] (...) [backend=z3] [reason=counterexample] + out.cpp:48:3: error: verification failed: read_after_miss [initialization] [backend=z3] [reason=counterexample] + 48 | return a; + | ^ + out.cpp:46:3: note: creates a local object at address 4 + 46 | int a; + | ^ + out.cpp:47:3: note: calls try_get(4, false) + 47 | try_get(a, false); + | ^ Verified: copied [backend=z3] out.cpp:65:3: Unresolved: copied_garbage [backend=z3] [reason=construct.unsupported] (the verifier cannot model a construct here: binding a reference or pointer parameter to storage that is not initialized, which the callee may read before writing it) - out.cpp:74:3: error: verification failed: read_too_early [...::initialization@74:3] (...) [backend=z3] [reason=counterexample] + out.cpp:74:3: error: verification failed: read_too_early [initialization] [backend=z3] [reason=counterexample] + 74 | int copy = r; + | ^ + out.cpp:74:3: note: counterexample: &r = 4 + out.cpp:72:3: note: creates a local object at address 4 + 72 | int a; + | ^ - ``copy_to``'s ``to`` is an out-parameter and ``from`` an input: ``copied_garbage`` passes ``b`` uninitialized, which ``copy_to`` reads. @@ -413,7 +427,11 @@ a pointer into an object the caller may write: Verified: put [backend=z3] Verified: set_third [backend=z3] Verified: set_through_copy [backend=z3] - frames.cpp:30:3: error: verification failed: set_fourth [...::frame@30:3] (counterexample: a [ssa=a_0] [type=pointer] = 1; trace: call.put@30:3 arg0=13 arg1=5) [backend=z3] [reason=counterexample] + frames.cpp:30:3: error: verification failed: set_fourth [frame] [backend=z3] [reason=counterexample] + 30 | put(a + 3, 5); + | ^ + frames.cpp:30:3: note: counterexample: a = 1 + frames.cpp:30:3: note: calls put(13, 5) ``set_fourth`` may write only ``a[2]``, at address 9 when ``a`` is 1, but passes ``a + 3``, address 13. A pointer-taking @@ -528,7 +546,10 @@ end but may not start one before the beginning: .. code-block:: text Verified: total [backend=z3] - walk.cpp:22:3: error: verification failed: back_one [...] (counterexample: ...) [backend=z3] [reason=counterexample] + walk.cpp:22:3: error: verification failed: back_one [bounds] [backend=z3] [reason=counterexample] + 22 | --q; + | ^ + walk.cpp:22:3: note: counterexample: a = 1, n = 1, q = 1 The value of a step inside an expression, as in ``*q++`` or ``while (*q++ != 0)``, is not supported yet: write the read and the step as @@ -577,7 +598,10 @@ Each index must lie in its array, an obligation of kind ``bounds``: Verified: popcount8 [backend=z3] Verified: hex_digit [backend=z3] - tables.cpp:21:3: error: verification failed: outside [...::bounds@21:3] (counterexample: x [ssa=x_0] [type=i32] = ...) [backend=z3] [reason=counterexample] + tables.cpp:21:3: error: verification failed: outside [bounds] [backend=z3] [reason=counterexample] + 21 | return NibbleBits[x]; + | ^ + tables.cpp:21:3: note: counterexample: x = -1 The verifier gives each table to the solver as a function of the index, defined by a balanced tree of comparisons, so a 256-entry table is eight @@ -687,7 +711,10 @@ with one null operand is undefined and fails: .. code-block:: text Verified: two_nulls [backend=z3] - nulls.cpp:11:3: error: verification failed: one_null [...::pointer-difference@11:3] (counterexample: p [ssa=p_0] [type=pointer] = 0, q [ssa=q_0] [type=pointer] = 1; ...) [backend=z3] [reason=counterexample] + nulls.cpp:11:3: error: verification failed: one_null [pointer-difference] [backend=z3] [reason=counterexample] + 11 | return p - q; + | ^ + nulls.cpp:11:3: note: counterexample: p = 0, q = 1 Before 0.2, ``two_nulls`` failed the same way. @@ -764,7 +791,10 @@ type: .. code-block:: text Verified: get [backend=z3] - error: verification failed: past_end [...::bounds@10:10] + example.cpp:10:10: error: verification failed: past_end [bounds] [backend=z3] [reason=counterexample] + 10 | { return p[n]; } + | ^ + example.cpp:10:10: note: counterexample: p = 1, n = 1 The marker means ``n >= 0``. A positive extent also means ``p`` is non-null and abstractly valid; an extent of zero permits null. Every ``p[i]`` or ``*(p + i)`` @@ -981,7 +1011,11 @@ where it points; the elements must lie in the objects it may address: Verified: first [backend=z3] Verified: second [backend=z3] - slices.cpp:20:3: error: verification failed: third [...::bounds@20:3] (counterexample: a [ssa=a_0] [type=pointer] = 1, q [ssa=q_1] [type=pointer] = 9; trace: call.first@20:3 arg0=9 arg1=3) [backend=z3] [reason=counterexample] + slices.cpp:20:3: error: verification failed: third [bounds] [backend=z3] [reason=counterexample] + 20 | return first(q, 3); + | ^ + slices.cpp:20:3: note: counterexample: a = 1, q = 9 + slices.cpp:20:3: note: calls first(9, 3) ``third`` passes three elements from ``a + 2``, of which only two are in ``a``: with ``a`` at address 1, ``q`` is 9, and the call would read up to From a9a64ade095eba26bf81e5f0e68f47002bf7cf1c Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 02:26:31 +0530 Subject: [PATCH 165/259] docs: Show failures as Clang diagnostics in the structs reference. --- website/source/language/structs.rst | 77 +++++++++++++++++++++++++---- 1 file changed, 68 insertions(+), 9 deletions(-) diff --git a/website/source/language/structs.rst b/website/source/language/structs.rst index 296e2830d1..783564d35f 100644 --- a/website/source/language/structs.rst +++ b/website/source/language/structs.rst @@ -84,7 +84,10 @@ footprint, bind a reference to it, and pass it to a reference parameter. Verified: peek [backend=z3] Verified: put [backend=z3] - ring.cpp:25:3: error: verification failed: slot [...::bounds@25:3] (counterexample: i [ssa=i_0] [type=i32] = 8, r [ssa=r_0] [type=pointer] = 1; ...) [backend=z3] [reason=counterexample] + ring.cpp:25:3: error: verification failed: slot [bounds] [backend=z3] [reason=counterexample] + 25 | return r->buf[i]; + | ^ + ring.cpp:25:3: note: counterexample: r = 1, i = 8 Each index is checked against its own array, as Frama-C's RTE guards are, and not only against the object. ``r->buf[8]`` has the address of @@ -196,7 +199,10 @@ of bounds: Verified: first [backend=z3] Verified: oldest [backend=z3] Verified: total [backend=z3] - ring.cpp:41:10: error: verification failed: past [...::bounds@41:10#2] (counterexample: q [ssa=q_1] [type=pointer] = 1, r [ssa=r_0] [type=pointer] = 1) [backend=z3] [reason=counterexample] + ring.cpp:41:10: error: verification failed: past [bounds] [backend=z3] [reason=counterexample] + 41 | return q[8]; + | ^ + ring.cpp:41:10: note: counterexample: r = 1, q = 1 The rules follow C++: @@ -311,7 +317,11 @@ parameter may be bound to a reference, to ``*p``, to a field such as Verified: reset [backend=z3] Verified: reset_left [backend=z3] Verified: bump_left [backend=z3] - pair.cpp:46:3: error: verification failed: reset_count [...::frame@46:3] (counterexample: p [ssa=p_0] [type=pointer] = 1; trace: call.reset@46:3 arg0=1) [backend=z3] [reason=counterexample] + pair.cpp:46:3: error: verification failed: reset_count [frame] [backend=z3] [reason=counterexample] + 46 | reset(p.left); + | ^ + pair.cpp:46:3: note: counterexample: &p = 1 + pair.cpp:46:3: note: calls reset(1) ``reset_left`` may write ``p.left``, which holds the whole object ``reset`` may write, so ``p.right`` keeps its value. ``reset_count`` may write only @@ -509,7 +519,22 @@ leaves ``b.len`` alone; two buffers through pointers to const may be one. Verified: zero [backend=z3] Verified: zero_prefix [backend=z3] - buf.cpp:39:3: error: verification failed: zero_more [...::bounds@39:3] (counterexample: n [ssa=n_0] [type=i32] = 0, p [ssa=p_0] [type=pointer] = 1; trace: allocation.automatic allocation@36:3 address=231056 provenance=18 -> heap-write.store@37:10 address=231056 value=1 -> heap-write.store@38:9 address=231064 value=1 -> call.zero@39:3 arg0=231056) [backend=z3] [reason=counterexample] + buf.cpp:39:3: error: verification failed: zero_more [bounds] [backend=z3] [reason=counterexample] + 39 | zero(b); + | ^ + buf.cpp:39:3: note: counterexample: p = 1, n = 0 + buf.cpp:36:3: note: creates a local object at address 231056 + 36 | Buf b; + | ^ + buf.cpp:37:10: note: stores 1 at address 231056 + 37 | b.data = p; + | ^ + buf.cpp:38:9: note: stores 1 at address 231064 + 38 | b.len = n + 1; + | ^ + buf.cpp:39:3: note: calls zero(231056) + 39 | zero(b); + | ^ ``zero_more`` passes a buffer one element longer than the extent of ``p``. A field given another pointer in the body (``b.data = q;``) addresses that @@ -605,8 +630,16 @@ free function. Verified: Counter::reset [backend=z3] Verified: Counter::copy_from [backend=z3] Verified: counted [backend=z3] - counter.cpp:49:5: error: verification failed: reset_count [...::frame@49:5] (counterexample: c [ssa=c_0] [type=pointer] = 1; trace: call.reset@49:5 arg0=1) [backend=z3] [reason=counterexample] - counter.cpp:55:5: error: verification failed: self_copy [...::aliasing@55:5] (counterexample: c [ssa=c_0] [type=pointer] = 1; trace: call.copy_from@55:5 arg0=1 arg1=1) [backend=z3] [reason=counterexample] + counter.cpp:49:5: error: verification failed: reset_count [frame] [backend=z3] [reason=counterexample] + 49 | c.reset(); + | ^ + counter.cpp:49:5: note: counterexample: &c = 1 + counter.cpp:49:5: note: calls reset(1) + counter.cpp:55:5: error: verification failed: self_copy [aliasing] [backend=z3] [reason=counterexample] + 55 | c.copy_from(c); + | ^ + counter.cpp:55:5: note: counterexample: &c = 1 + counter.cpp:55:5: note: calls copy_from(1, 1) ``reset`` states no ``cppverify::modifies``, so it may write all of ``c``, which ``reset_count`` may not. ``copy_from`` writes ``this->n`` and reads @@ -748,7 +781,19 @@ object after the call: .. code-block:: text Verified: Ring::Ring [backend=z3] - ring.cpp:24:7: error: verification failed: Ring::Ring [...::initialization@24:7#2] (counterexample: ...) [backend=z3] [reason=counterexample] + ring.cpp:24:7: error: verification failed: Ring::Ring [initialization] [backend=z3] [reason=counterexample] + 24 | int buf[8]; + | ^ + ring.cpp:24:7: note: counterexample: this = 11798, first = 0 + ring.cpp:19:7: note: stores 0 at address 11830 + 19 | : head(0), count(1) + | ^ + ring.cpp:19:16: note: stores 1 at address 11834 + 19 | : head(0), count(1) + | ^ + ring.cpp:21:12: note: stores 0 at address 11798 + 21 | buf[0] = first; + | ^ Verified: fresh [backend=z3] The second constructor initializes ``buf[0]`` alone, and the failure is @@ -876,7 +921,13 @@ internal calls included, so no call observes the object while it is broken: Verified: Meter::Meter [backend=z3] Verified: Meter::add [backend=z3] - meter.cpp:28:33: error: verification failed: Meter::overflow [...::type-invariant@28:33] (counterexample: ...) [backend=z3] [reason=counterexample] + meter.cpp:28:33: error: verification failed: Meter::overflow [type-invariant] [backend=z3] [reason=counterexample] + 28 | cv::type_invariant(0 <= level && level <= 100); + | ~~~~~~~~~~~^~~~~~~~~~~~~~~ + meter.cpp:28:33: note: counterexample: this = 1 + meter.cpp:17:11: note: stores 101 at address 1 + 17 | level = 101; + | ^ Verified: Meter::get [backend=z3] Verified: filled [backend=z3] @@ -951,8 +1002,16 @@ it, and the class's type invariants with the class. Verified: Box::Box [backend=z3] Verified: Box::twice [backend=z3] Verified: Box::Box [backend=z3] - box.cpp:10:25: error: verification failed: Box::twice [...::postcondition@10:25] (counterexample: ...) [backend=z3] [reason=counterexample] + box.cpp:10:25: error: verification failed: Box::twice [postcondition] [backend=z3] [reason=counterexample] + 10 | cv::post(cv::result == 2 * value) + | ~~~~~~~~~~~^~~~~~~~~~~~ + box.cpp:10:25: note: counterexample: this = 1, result = -32768 + box.cpp:12:5: note: returns -32768 + 12 | return value + value; + | ^ box.cpp:33:15: note: in instantiation of member function 'Box::twice' requested here + 33 | short d = b.twice(); + | ^ Verified: doubled [backend=z3] Unresolved: doubled_short [backend=z3] [reason=callee.contract] (relies on the contract of Box::twice, which is not established) From 90ba3694559a3611877545c2e3f8df839e6b10d1 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 03:04:24 +0530 Subject: [PATCH 166/259] test: Check undecided steps and a check failing in an arbitrary loop iteration. --- clang/test/Verify/suite/failure_notes.cpp | 37 +++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/clang/test/Verify/suite/failure_notes.cpp b/clang/test/Verify/suite/failure_notes.cpp index 91f99eca89..06ad3a2a0c 100644 --- a/clang/test/Verify/suite/failure_notes.cpp +++ b/clang/test/Verify/suite/failure_notes.cpp @@ -251,6 +251,43 @@ int two_lines(int x) // JSON keeps every version, and marks those of branches the path does not // take. +// A step the counterexample does not decide is marked. +int undecided(bool choose) + cv::post(cv::result == 0) +{ + if (choose) { + } else { + } + return 1; +} +// CHECK: {{.*}}failure_notes.cpp:[[@LINE-7]]:23: error: verification failed: undecided [postcondition] [backend=z3] [reason=counterexample] +// CHECK: {{.*}}failure_notes.cpp:[[@LINE-6]]:3: note: perhaps takes the true branch (the counterexample does not decide whether this step is taken) +// CHECK-NEXT: {{^ *}}[[@LINE-7]] | if (choose) {{{$}} +// CHECK-NEXT: {{^}} | ^{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-9]]:3: note: perhaps takes the false branch (the counterexample does not decide whether this step is taken) + +// A check inside a loop fails in an arbitrary iteration of it. +int iterate(int n) + cv::pre(0 <= n && n <= 5) + cv::post(cv::result == n) +{ + int i = 0; + while (i < n) + cv::invariant(0 <= i && i <= n) + cv::decreases(n - i) + { + cv::check(i < 4); + i = i + 1; + } + return i; +} +// CHECK: {{.*}}failure_notes.cpp:[[@LINE-5]]:5: error: verification failed: iterate [assertion] [backend=z3] [reason=counterexample] +// CHECK: {{.*}}failure_notes.cpp:[[@LINE-6]]:5: note: counterexample: n = [[N:[45]]], i = 0 -> 4 +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-11]]:3: note: enters the loop +// CHECK-NEXT: {{^ *}}[[@LINE-12]] | while (i < n){{$}} +// CHECK-NEXT: {{^}} | ^{{$}} +// CHECK-NEXT: {{.*}}failure_notes.cpp:[[@LINE-14]]:3: note: starts an arbitrary iteration of the loop, where its condition is true + // An archive keeps where each version is defined, so its replay lists the // same values. // REPLAY: error: verification failed: steps [postcondition] From fcaa64134bb4500872ca63fa96b9a3c38bcc7458 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:30 +0530 Subject: [PATCH 167/259] verify: Record where a source range begins, apart from its anchor. --- clang/lib/Verify/Backend/Obligation.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/clang/lib/Verify/Backend/Obligation.h b/clang/lib/Verify/Backend/Obligation.h index 3998753961..5503fa10b4 100644 --- a/clang/lib/Verify/Backend/Obligation.h +++ b/clang/lib/Verify/Backend/Obligation.h @@ -139,15 +139,24 @@ std::string formatLogicFeatures(LogicFeatureSet Features); const char *logicSortName(LogicSortKind Kind); std::string formatLogicSort(const LogicSort &Sort); +/// Where a term comes from: its anchor (Line, Column), where a diagnostic +/// points and a stable ID is built, in the source it spans, from its begin to +/// the column after its last character. struct ObligationSource { std::string File; unsigned Line = 0; unsigned Column = 0; unsigned EndLine = 0; unsigned EndColumn = 0; + /// The start of the span, before the anchor (an operator's operands); + /// zero when it is the anchor. + unsigned BeginLine = 0; + unsigned BeginColumn = 0; bool isValid() const { return !File.empty() && Line != 0; } bool hasRange() const { return isValid() && EndLine != 0; } + unsigned beginLine() const { return BeginLine ? BeginLine : Line; } + unsigned beginColumn() const { return BeginLine ? BeginColumn : Column; } }; class LogicExpr; From ec625f51cd0a9ca7164ee278c8028e04d50ec620 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:30 +0530 Subject: [PATCH 168/259] verify: Reject a source range that begins after its anchor. --- clang/lib/Verify/Backend/Obligation.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/clang/lib/Verify/Backend/Obligation.cpp b/clang/lib/Verify/Backend/Obligation.cpp index 976d229d1d..8c9b6aab51 100644 --- a/clang/lib/Verify/Backend/Obligation.cpp +++ b/clang/lib/Verify/Backend/Obligation.cpp @@ -553,6 +553,15 @@ static bool validateSource(const ObligationSource &Source, std::string &Error) { Error = "source range end precedes its start"; return false; } + if ((Source.BeginLine == 0) != (Source.BeginColumn == 0)) { + Error = "source range has an incomplete begin"; + return false; + } + if (Source.BeginLine > Source.Line || + (Source.BeginLine == Source.Line && Source.BeginColumn > Source.Column)) { + Error = "source range begins after its anchor"; + return false; + } return true; } From 235adfe4222d48914f0ce6ee7ee7c8b4f9bbfedb Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:31 +0530 Subject: [PATCH 169/259] verify: Move obligation archives to schema v5. --- clang/lib/Verify/Backend/ObligationSerialization.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/lib/Verify/Backend/ObligationSerialization.h b/clang/lib/Verify/Backend/ObligationSerialization.h index 7bb75427dd..51dc220056 100644 --- a/clang/lib/Verify/Backend/ObligationSerialization.h +++ b/clang/lib/Verify/Backend/ObligationSerialization.h @@ -15,7 +15,7 @@ namespace verify { /// Version 2 adds the precise obligation kinds; version 3 each logical /// function's termination measures and, with source metadata, where each /// assumption of a goal comes from. Readers read every earlier version. -inline constexpr uint32_t ObligationSerializationVersion = 4; +inline constexpr uint32_t ObligationSerializationVersion = 5; inline constexpr uint32_t ObligationSemanticHashVersion = 4; /// Serialize one module as a deterministic, versioned binary record. Records From b7cab520a975a7e336d86b7d4996f32605063b38 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:31 +0530 Subject: [PATCH 170/259] verify: Archive where each source range begins, from schema v5. --- clang/lib/Verify/Backend/ObligationSerialization.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/clang/lib/Verify/Backend/ObligationSerialization.cpp b/clang/lib/Verify/Backend/ObligationSerialization.cpp index f15b9cdbca..46b0dd7ade 100644 --- a/clang/lib/Verify/Backend/ObligationSerialization.cpp +++ b/clang/lib/Verify/Backend/ObligationSerialization.cpp @@ -444,6 +444,7 @@ std::optional traceFromTag(uint8_t Tag) { class ArchiveWriter { std::string Data; + uint32_t FormatVersion = ObligationSerializationVersion; bool IncludeSource; bool IncludeSourceRanges; bool IncludeDiagnostics; @@ -487,6 +488,10 @@ class ArchiveWriter { if (IncludeSourceRanges) { writeU32(Source.EndLine); writeU32(Source.EndColumn); + if (FormatVersion >= 5) { + writeU32(Source.BeginLine); + writeU32(Source.BeginColumn); + } } } @@ -560,6 +565,7 @@ class ArchiveWriter { void writeModule(const ObligationModule &Module, uint32_t FormatVersion = ObligationSerializationVersion) { + this->FormatVersion = FormatVersion; Data.append(ArchiveMagic.data(), ArchiveMagic.size()); writeU32(FormatVersion); uint32_t Flags = IncludeSource ? HasSourceMetadata : 0; @@ -788,6 +794,10 @@ class ArchiveReader { if (IncludeSourceRanges) { Source.EndLine = readU32(); Source.EndColumn = readU32(); + if (Version >= 5) { + Source.BeginLine = readU32(); + Source.BeginColumn = readU32(); + } } return Source; } From 67eea9b97a8def5e0fb6cadbdcb867a58c4d9504 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:32 +0530 Subject: [PATCH 171/259] verify: Carry the function of a conversion error with its location. --- clang/lib/Verify/Frontend/ASTConverter.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/clang/lib/Verify/Frontend/ASTConverter.h b/clang/lib/Verify/Frontend/ASTConverter.h index dfc350c871..fd425c3bc5 100644 --- a/clang/lib/Verify/Frontend/ASTConverter.h +++ b/clang/lib/Verify/Frontend/ASTConverter.h @@ -20,6 +20,7 @@ struct ConversionError { /// decides; empty for an error of the translation unit. std::string Function; std::string FunctionName; + SourceLocation FunctionLoc; /// In the function's signature or contract, rather than its body: then /// its callers cannot use the contract either. bool InContract = false; @@ -55,16 +56,17 @@ class ASTConverter { /// converter is in its signature and contract or in its body. std::string ErrorFunction; std::string ErrorFunctionName; + SourceLocation ErrorFunctionLoc; bool ErrorInContract = false; void error(std::string Message) { error(CurrentRange, std::move(Message)); } void error(SourceRange Range, std::string Message) { Errors.push_back({Range, std::move(Message), ErrorFunction, - ErrorFunctionName, ErrorInContract}); + ErrorFunctionName, ErrorFunctionLoc, ErrorInContract}); } /// An error about \p Fn found once every function is converted. void errorOf(const VFunction &Fn, SourceLocation Loc, std::string Message) { - Errors.push_back( - {SourceRange(Loc), std::move(Message), Fn.Identity, Fn.Name, false}); + Errors.push_back({SourceRange(Loc), std::move(Message), Fn.Identity, + Fn.Name, Fn.DeclLoc, false}); } std::vector> Warnings; /// Maps unqualified field name -> "param." for type_invariant lowering. From e39f73aa3396abb0a0cf9759feeca90a936ed5d7 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:32 +0530 Subject: [PATCH 172/259] verify: Record the location of the function a conversion error belongs to. --- clang/lib/Verify/Frontend/ASTConverter.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clang/lib/Verify/Frontend/ASTConverter.cpp b/clang/lib/Verify/Frontend/ASTConverter.cpp index b7a5dbac7f..69911b546e 100644 --- a/clang/lib/Verify/Frontend/ASTConverter.cpp +++ b/clang/lib/Verify/Frontend/ASTConverter.cpp @@ -2432,6 +2432,7 @@ std::vector> ASTConverter::convertTranslationUnit() { } llvm::SaveAndRestore Owner(ErrorFunction, functionIdentity(FD)); llvm::SaveAndRestore OwnerName(ErrorFunctionName, functionName(FD)); + llvm::SaveAndRestore OwnerLoc(ErrorFunctionLoc, FD->getLocation()); llvm::SaveAndRestore InContract(ErrorInContract, true); error(FD->getLocation(), FD->getQualifiedNameAsString() + ": " + *UnsupportedMember); @@ -3245,6 +3246,7 @@ ASTConverter::convertFunction(const FunctionDecl *FD) { llvm::SaveAndRestore At(CurrentRange, SourceRange(FD->getLocation())); llvm::SaveAndRestore Owner(ErrorFunction, functionIdentity(FD)); llvm::SaveAndRestore OwnerName(ErrorFunctionName, functionName(FD)); + llvm::SaveAndRestore OwnerLoc(ErrorFunctionLoc, FD->getLocation()); llvm::SaveAndRestore InContract(ErrorInContract, true); const size_t ErrorsAtStart = Errors.size(); const FunctionContractInfo *FCI = functionContract(FD); @@ -4266,6 +4268,7 @@ std::unique_ptr ASTConverter::convertConstexprSpec(const FunctionDecl *FD) { llvm::SaveAndRestore Owner(ErrorFunction, functionIdentity(FD)); llvm::SaveAndRestore OwnerName(ErrorFunctionName, functionName(FD)); + llvm::SaveAndRestore OwnerLoc(ErrorFunctionLoc, FD->getLocation()); llvm::SaveAndRestore InContract(ErrorInContract, true); const size_t ErrorsAtStart = Errors.size(); nameParameters(FD, FD); From 9b6d70c3dd0b822b6225b32340a09fb573deef56 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:33 +0530 Subject: [PATCH 173/259] verify: Declare the JSON, SARIF, and GitHub output helpers. --- clang/lib/Verify/Driver/StructuredOutput.h | 44 ++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 clang/lib/Verify/Driver/StructuredOutput.h diff --git a/clang/lib/Verify/Driver/StructuredOutput.h b/clang/lib/Verify/Driver/StructuredOutput.h new file mode 100644 index 0000000000..8ca9d47460 --- /dev/null +++ b/clang/lib/Verify/Driver/StructuredOutput.h @@ -0,0 +1,44 @@ +//===--- StructuredOutput.h - JSON, SARIF, and GitHub output ----*- C++ -*-===// +#ifndef LLVM_CLANG_VERIFY_DRIVER_STRUCTUREDOUTPUT_H +#define LLVM_CLANG_VERIFY_DRIVER_STRUCTUREDOUTPUT_H + +#include "../Backend/Obligation.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/JSON.h" +#include +#include + +namespace clang { +namespace verify { + +inline constexpr const char DiagnosticSchema[] = "cppverify.diagnostic/2"; +inline constexpr const char SummarySchema[] = "cppverify.summary/1"; + +/// Text as JSON takes it: invalid UTF-8 replaced. +std::string jsonText(llvm::StringRef Text); + +/// The source a term spans, from its first column to the one after its last. +llvm::json::Object sourceJSON(const ObligationSource &Source); + +/// A GitHub workflow command that annotates Source (an error, a warning, or a +/// notice) with Title and Message. +std::string githubCommand(llvm::StringRef Level, const ObligationSource &Source, + llvm::StringRef Title, llvm::StringRef Message); + +/// How the run that produced the records went. +struct SarifInvocation { + std::string Version; + std::vector Arguments; + int ExitCode = 0; +}; + +/// A SARIF 2.1.0 log of the records of a run: cppverify.diagnostic/2 records +/// become results, and the summary and time records the run's properties. +llvm::json::Value sarifLog(llvm::ArrayRef Records, + const SarifInvocation &Invocation); + +} // namespace verify +} // namespace clang + +#endif From 0268240106a12672b3290efc100ddc983fb9ee3b Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:33 +0530 Subject: [PATCH 174/259] verify: Build SARIF logs and GitHub workflow commands from diagnostic records. --- clang/lib/Verify/Driver/StructuredOutput.cpp | 380 +++++++++++++++++++ 1 file changed, 380 insertions(+) create mode 100644 clang/lib/Verify/Driver/StructuredOutput.cpp diff --git a/clang/lib/Verify/Driver/StructuredOutput.cpp b/clang/lib/Verify/Driver/StructuredOutput.cpp new file mode 100644 index 0000000000..60e651ab48 --- /dev/null +++ b/clang/lib/Verify/Driver/StructuredOutput.cpp @@ -0,0 +1,380 @@ +//===--- StructuredOutput.cpp - JSON, SARIF, and GitHub output ------------===// +#include "StructuredOutput.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include + +using namespace clang; +using namespace clang::verify; + +std::string verify::jsonText(llvm::StringRef Text) { + return llvm::json::isUTF8(Text) ? Text.str() : llvm::json::fixUTF8(Text); +} + +llvm::json::Object verify::sourceJSON(const ObligationSource &Source) { + llvm::json::Object Result; + if (!Source.isValid()) + return Result; + Result["file"] = jsonText(Source.File); + Result["line"] = Source.beginLine(); + Result["column"] = Source.beginColumn(); + Result["end_line"] = Source.EndLine != 0 ? Source.EndLine : Source.Line; + Result["end_column"] = + Source.EndColumn != 0 ? Source.EndColumn : Source.Column; + return Result; +} + +namespace { +/// The workflow command escapes of GitHub Actions: data escapes '%' and line +/// ends, a property also ':' and ','. +std::string escapeCommand(llvm::StringRef Text, bool Property) { + std::string Out; + for (char C : Text) { + switch (C) { + case '%': + Out += "%25"; + break; + case '\r': + Out += "%0D"; + break; + case '\n': + Out += "%0A"; + break; + case ':': + Out += Property ? "%3A" : ":"; + break; + case ',': + Out += Property ? "%2C" : ","; + break; + default: + Out += C; + } + } + return Out; +} + +/// A path as GitHub resolves it: relative to the working directory, the +/// checkout in a workflow, when it lies under it. +std::string workspacePath(llvm::StringRef File) { + llvm::SmallString<256> Directory; + if (llvm::sys::path::is_absolute(File) && + !llvm::sys::fs::current_path(Directory)) { + Directory += llvm::sys::path::get_separator(); + if (File.starts_with(Directory)) + return File.drop_front(Directory.size()).str(); + } + return File.str(); +} + +/// An absolute file URI, as Clang writes it in SARIF. +std::string fileURI(llvm::StringRef File) { + llvm::SmallString<256> Path(File); + llvm::sys::fs::make_absolute(Path); + llvm::sys::path::native(Path, llvm::sys::path::Style::posix); + std::string URI = "file://"; + if (!llvm::StringRef(Path).starts_with("/")) + URI += "/"; + for (char C : Path) { + if (llvm::isAlnum(C) || llvm::StringRef("-._~/:").contains(C)) + URI += C; + else + URI += "%" + llvm::utohexstr(static_cast(C), false, 2); + } + return URI; +} + +std::string text(const llvm::json::Object &Record, llvm::StringRef Key) { + if (std::optional Value = Record.getString(Key)) + return Value->str(); + return ""; +} + +struct Classification { + std::string Rule; + std::string Kind; + std::string Level; +}; + +/// The SARIF rule, kind, and level of a record, after Frama-C's mapping of +/// property statuses: a proof passes, a failure fails, what no verdict +/// settles stays open. +Classification classify(const llvm::json::Object &Record) { + const std::string Status = text(Record, "status"); + const std::string Severity = text(Record, "severity"); + if (Status == "failed") { + std::string Rule = "failed"; + if (const llvm::json::Object *Obligation = Record.getObject("obligation")) + if (std::optional Kind = Obligation->getString("kind")) + Rule = Kind->str(); + return {Rule, "fail", "error"}; + } + if (Status == "verified" || Status == "certified" || + Status == "mixed-proof" || Status == "proved-obligations") + return {"verified", "pass", "none"}; + if (Status == "unresolved" || Status == "interrupted") + return {Status, "open", "error"}; + if (Status == "bounded-safe") + return {Status, "open", "warning"}; + if (Status == "trusted") + return {Status, "review", "none"}; + if (Status == "exported") + return {Status, "open", "note"}; + if (Status == "lowered") + return {Status, "informational", "none"}; + if (Status == "frontend") + return {"frontend", + Severity == "error" || Severity == "warning" ? "fail" + : "informational", + Severity == "error" || Severity == "warning" ? Severity : "note"}; + if (Severity == "warning") + return {"warning", "fail", "warning"}; + return {Status.empty() ? "error" : Status, "fail", + Severity == "error" ? "error" : "note"}; +} + +std::string ruleDescription(llvm::StringRef Rule) { + if (Rule == "verified") + return "The function's contract is proved."; + if (Rule == "unresolved") + return "No verdict settles the function; the reason says why."; + if (Rule == "interrupted") + return "The run was interrupted before the function's verification ended."; + if (Rule == "bounded-safe") + return "No check fails within the unrolling bound."; + if (Rule == "trusted") + return "The contract is assumed, not verified."; + if (Rule == "exported") + return "The obligations are exported to Lean, not yet certified."; + if (Rule == "lowered") + return "The obligations are lowered; no solver ran."; + if (Rule == "frontend") + return "A diagnostic of the compiler."; + if (Rule == "warning") + return "A warning of the verifier."; + if (Rule == "failed" || Rule == "error") + return "Verification failed."; + return ("A " + Rule + " check fails.").str(); +} + +/// What the text output prints before a verdict's message, which a record +/// leaves to its status. +std::string verdictPrefix(llvm::StringRef Status) { + static const std::pair Prefixes[] = { + {"verified", "Verified: "}, + {"certified", "Certified: "}, + {"mixed-proof", "Proved: "}, + {"proved-obligations", "Proved obligations: "}, + {"unresolved", "Unresolved: "}, + {"interrupted", "Interrupted: "}, + {"bounded-safe", "BoundedSafe: "}, + {"trusted", "Trusted: "}, + {"exported", "Exported: "}, + {"lowered", "Lowered: "}}; + for (const auto &[Name, Prefix] : Prefixes) + if (Status == Name) + return Prefix; + return ""; +} + +llvm::json::Object region(const llvm::json::Object &Source) { + static const std::pair Fields[] = { + {"line", "startLine"}, + {"column", "startColumn"}, + {"end_line", "endLine"}, + {"end_column", "endColumn"}}; + llvm::json::Object Region; + for (const auto &[From, To] : Fields) + if (std::optional Value = Source.getInteger(From)) + Region[To] = *Value; + return Region; +} +} // namespace + +std::string verify::githubCommand(llvm::StringRef Level, + const ObligationSource &Source, + llvm::StringRef Title, + llvm::StringRef Message) { + std::vector Properties; + if (Source.isValid()) { + Properties.push_back("file=" + + escapeCommand(workspacePath(Source.File), true)); + Properties.push_back("line=" + std::to_string(Source.beginLine())); + Properties.push_back("col=" + std::to_string(Source.beginColumn())); + if (Source.EndLine) { + Properties.push_back("endLine=" + std::to_string(Source.EndLine)); + Properties.push_back("endColumn=" + std::to_string(Source.EndColumn)); + } + } + if (!Title.empty()) + Properties.push_back("title=" + escapeCommand(Title, true)); + std::string Command = "::" + Level.str(); + if (!Properties.empty()) + Command += " " + llvm::join(Properties, ","); + return Command + "::" + escapeCommand(Message, false) + "\n"; +} + +llvm::json::Value verify::sarifLog(llvm::ArrayRef Records, + const SarifInvocation &Invocation) { + std::vector> RuleLevels; + std::map RuleIndex; + std::vector Files; + std::map FileIndex; + auto physical = [&](const llvm::json::Object &Source) { + llvm::json::Object Location; + const std::string File = text(Source, "file"); + if (File.empty()) + return Location; + const std::string URI = fileURI(File); + auto [It, Inserted] = FileIndex.try_emplace(URI, Files.size()); + if (Inserted) + Files.push_back(URI); + Location["artifactLocation"] = llvm::json::Object{ + {"uri", URI}, {"index", static_cast(It->second)}}; + Location["region"] = region(Source); + return Location; + }; + + llvm::json::Array Results; + llvm::json::Object Properties; + llvm::json::Array Times; + for (const llvm::json::Value &Value : Records) { + const llvm::json::Object *Record = Value.getAsObject(); + if (!Record) + continue; + const std::string Schema = text(*Record, "schema"); + if (Schema == SummarySchema) { + Properties["summary"] = llvm::json::Value(llvm::json::Object(*Record)); + continue; + } + if (Schema != DiagnosticSchema) { + Times.push_back(llvm::json::Object(*Record)); + continue; + } + Classification Class = classify(*Record); + auto [It, Inserted] = RuleIndex.try_emplace(Class.Rule, RuleLevels.size()); + if (Inserted) + RuleLevels.emplace_back(Class.Rule, + Class.Level == "none" ? "note" : Class.Level); + + llvm::json::Object Result; + Result["ruleId"] = Class.Rule; + Result["ruleIndex"] = static_cast(It->second); + Result["kind"] = Class.Kind; + Result["level"] = Class.Level; + std::string Message = + verdictPrefix(text(*Record, "status")) + text(*Record, "message"); + if (std::string Values = text(*Record, "counterexample"); !Values.empty()) + Message += "\ncounterexample: " + Values; + if (const llvm::json::Array *Notes = Record->getArray("notes")) + for (const llvm::json::Value &Note : *Notes) + if (std::optional Line = Note.getAsString()) + Message += "\n" + Line->str(); + Result["message"] = llvm::json::Object{{"text", Message}}; + + const llvm::json::Object *Source = Record->getObject("source"); + if (!Source) + Source = Record->getObject("function_source"); + llvm::json::Object Location; + if (Source) + if (llvm::json::Object Physical = physical(*Source); !Physical.empty()) + Location["physicalLocation"] = std::move(Physical); + if (std::string Function = text(*Record, "function"); !Function.empty()) + Location["logicalLocations"] = llvm::json::Array{ + llvm::json::Object{{"name", Function}, {"kind", "function"}}}; + if (!Location.empty()) + Result["locations"] = llvm::json::Array{std::move(Location)}; + + if (const llvm::json::Array *Trace = Record->getArray("trace")) { + llvm::json::Array Steps; + for (const llvm::json::Value &Step : *Trace) { + const llvm::json::Object *Event = Step.getAsObject(); + if (!Event) + continue; + llvm::json::Object At; + if (const llvm::json::Object *StepSource = Event->getObject("source")) + if (llvm::json::Object Physical = physical(*StepSource); + !Physical.empty()) + At["physicalLocation"] = std::move(Physical); + At["message"] = llvm::json::Object{{"text", text(*Event, "text")}}; + Steps.push_back(llvm::json::Object{{"location", std::move(At)}}); + } + if (!Steps.empty()) + Result["codeFlows"] = llvm::json::Array{llvm::json::Object{ + {"threadFlows", llvm::json::Array{llvm::json::Object{ + {"locations", std::move(Steps)}}}}}}; + } + + if (const llvm::json::Array *Related = Record->getArray("related")) { + llvm::json::Array Locations; + for (const llvm::json::Value &Each : *Related) { + const llvm::json::Object *Note = Each.getAsObject(); + if (!Note) + continue; + llvm::json::Object At; + At["id"] = static_cast(Locations.size()); + if (const llvm::json::Object *NoteSource = Note->getObject("source")) + if (llvm::json::Object Physical = physical(*NoteSource); + !Physical.empty()) + At["physicalLocation"] = std::move(Physical); + At["message"] = llvm::json::Object{{"text", text(*Note, "message")}}; + Locations.push_back(std::move(At)); + } + if (!Locations.empty()) + Result["relatedLocations"] = std::move(Locations); + } + + llvm::json::Object Bag; + for (const char *Key : + {"status", "reason", "backend", "counterexample", "option"}) + if (std::string Value = text(*Record, Key); !Value.empty()) + Bag[Key] = Value; + if (const llvm::json::Object *Obligation = Record->getObject("obligation")) + if (std::optional Id = Obligation->getString("id")) + Bag["obligation"] = Id->str(); + if (!Bag.empty()) + Result["properties"] = std::move(Bag); + Results.push_back(std::move(Result)); + } + if (!Times.empty()) + Properties["times"] = std::move(Times); + + llvm::json::Array Rules; + for (const auto &[Id, Level] : RuleLevels) + Rules.push_back(llvm::json::Object{ + {"id", Id}, + {"shortDescription", llvm::json::Object{{"text", ruleDescription(Id)}}}, + {"helpUri", "https://swayaminsync.github.io/cpp-verify/language/" + "tooling.html#structured-diagnostics"}, + {"defaultConfiguration", llvm::json::Object{{"level", Level}}}}); + llvm::json::Array Artifacts; + for (const std::string &URI : Files) + Artifacts.push_back( + llvm::json::Object{{"location", llvm::json::Object{{"uri", URI}}}}); + llvm::json::Array Arguments; + for (const std::string &Argument : Invocation.Arguments) + Arguments.push_back(jsonText(Argument)); + + llvm::json::Object Run; + Run["tool"] = llvm::json::Object{ + {"driver", + llvm::json::Object{ + {"name", "cpp-verify"}, + {"version", Invocation.Version}, + {"informationUri", "https://swayaminsync.github.io/cpp-verify/"}, + {"rules", std::move(Rules)}}}}; + Run["invocations"] = llvm::json::Array{ + llvm::json::Object{{"arguments", std::move(Arguments)}, + {"executionSuccessful", Invocation.ExitCode != 130}, + {"exitCode", Invocation.ExitCode}}}; + Run["artifacts"] = std::move(Artifacts); + Run["columnKind"] = "unicodeCodePoints"; + Run["results"] = std::move(Results); + if (!Properties.empty()) + Run["properties"] = std::move(Properties); + return llvm::json::Object{ + {"$schema", "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/" + "schemas/sarif-schema-2.1.0.json"}, + {"version", "2.1.0"}, + {"runs", llvm::json::Array{std::move(Run)}}}; +} From 109f607b783ed999b125b0c59bebeb7bd1d100ec Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:33 +0530 Subject: [PATCH 175/259] verify: Build the structured output helpers. --- clang/lib/Verify/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/lib/Verify/CMakeLists.txt b/clang/lib/Verify/CMakeLists.txt index a9cc217db0..d6f3bcd682 100644 --- a/clang/lib/Verify/CMakeLists.txt +++ b/clang/lib/Verify/CMakeLists.txt @@ -49,6 +49,7 @@ add_clang_library(clangVerify Backend/LeanBackend.cpp Driver/Verifier.cpp Driver/Counterexample.cpp + Driver/StructuredOutput.cpp Driver/DumpIR.cpp Driver/CppVerifyIntegration.cpp Driver/CppVerifyVersion.cpp From 4deccbd998ebd03a49f9fdbbbb7c50edafd1b782 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:34 +0530 Subject: [PATCH 176/259] verify: Declare the release version for structured output. --- clang/lib/Verify/Driver/CppVerifyVersion.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/clang/lib/Verify/Driver/CppVerifyVersion.h b/clang/lib/Verify/Driver/CppVerifyVersion.h index dd759c8e9b..b60c543c4c 100644 --- a/clang/lib/Verify/Driver/CppVerifyVersion.h +++ b/clang/lib/Verify/Driver/CppVerifyVersion.h @@ -24,6 +24,9 @@ inline constexpr llvm::StringLiteral CVC5TestedVersion = "1.1.2"; /// verification run would find on PATH. void printVersion(llvm::raw_ostream &OS); +/// The release, as --version names it: "0.2.0-dev". +llvm::StringRef releaseVersion(); + } // namespace verify } // namespace clang From 08a2992d095a2427fdce753c65efe77dec104d53 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:34 +0530 Subject: [PATCH 177/259] verify: Return the release version as --version names it. --- clang/lib/Verify/Driver/CppVerifyVersion.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang/lib/Verify/Driver/CppVerifyVersion.cpp b/clang/lib/Verify/Driver/CppVerifyVersion.cpp index 19e6250e3c..991a74269d 100644 --- a/clang/lib/Verify/Driver/CppVerifyVersion.cpp +++ b/clang/lib/Verify/Driver/CppVerifyVersion.cpp @@ -116,6 +116,8 @@ void printLean(llvm::raw_ostream &OS) { } // namespace +llvm::StringRef verify::releaseVersion() { return CPPVERIFY_VERSION; } + void verify::printVersion(llvm::raw_ostream &OS) { OS << "cpp-verify " << CPPVERIFY_VERSION; std::string Repository = getClangFullRepositoryVersion(); From 4daacbf9f89af496feab689f9b55a4d39c80f2ce Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:35 +0530 Subject: [PATCH 178/259] verify: Add the GitHub diagnostics format. --- clang/lib/Verify/Driver/Verifier.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clang/lib/Verify/Driver/Verifier.h b/clang/lib/Verify/Driver/Verifier.h index 06ae6ee687..e36fa94467 100644 --- a/clang/lib/Verify/Driver/Verifier.h +++ b/clang/lib/Verify/Driver/Verifier.h @@ -25,7 +25,9 @@ inline constexpr unsigned DefaultCollectionTimeoutMs = inline constexpr unsigned DefaultFunctionTimeoutMs = 10 * DefaultSolverTimeoutMs; -enum class DiagnosticFormat { Text, Json }; +/// How results are printed: text, JSON Lines (cppverify.diagnostic/2), or +/// text with a GitHub workflow annotation after each error and warning. +enum class DiagnosticFormat { Text, Json, GitHub }; /// Which obligations of an unresolved module --lean-fallback exports. enum class LeanFallbackScope { From 4e99d16346cf975eb8e38172d3f0fac53a8bb0d2 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:35 +0530 Subject: [PATCH 179/259] verify: Print cppverify.diagnostic/2 records with exact ranges, and GitHub annotations. --- clang/lib/Verify/Driver/Verifier.cpp | 186 +++++++++++++++++---------- 1 file changed, 117 insertions(+), 69 deletions(-) diff --git a/clang/lib/Verify/Driver/Verifier.cpp b/clang/lib/Verify/Driver/Verifier.cpp index 43d0ce7f46..0f3d2421d0 100644 --- a/clang/lib/Verify/Driver/Verifier.cpp +++ b/clang/lib/Verify/Driver/Verifier.cpp @@ -28,9 +28,11 @@ #include "DumpIR.h" #include "LeanAutomation.h" #include "LeanCertifier.h" +#include "StructuredOutput.h" #include "clang/AST/ASTContext.h" #include "clang/Basic/SourceManager.h" #include "clang/Frontend/TextDiagnostic.h" +#include "clang/Lex/Lexer.h" #include "llvm/ADT/DenseSet.h" #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallString.h" @@ -1305,22 +1307,6 @@ static llvm::StringRef traceKindCode(DiagnosticTraceKind Kind) { return "branch"; } -static std::string jsonText(llvm::StringRef Text) { - return llvm::json::isUTF8(Text) ? Text.str() : llvm::json::fixUTF8(Text); -} - -static llvm::json::Object sourceJSON(const ObligationSource &Source) { - llvm::json::Object Result; - if (!Source.isValid()) - return Result; - Result["file"] = jsonText(Source.File); - Result["line"] = Source.Line; - Result["column"] = Source.Column; - Result["end_line"] = Source.EndLine != 0 ? Source.EndLine : Source.Line; - Result["end_column"] = - Source.EndColumn != 0 ? Source.EndColumn : Source.Column; - return Result; -} static std::string leanProjectPath(llvm::StringRef Root, llvm::ArrayRef Components) { @@ -2961,35 +2947,67 @@ class Verifier { return llvm::Error::success(); } - void annotateObligationSources(ObligationModule &Module) { + /// The source from BeginLoc to the end of the token at EndLoc, anchored at + /// Loc; in a macro, the source of its use. Empty when Loc has none. + ObligationSource sourceOf(SourceLocation Loc, SourceLocation BeginLoc, + SourceLocation EndLoc) const { const SourceManager &SourceMgr = Ctx.getSourceManager(); - auto annotateSource = [&](SourceLocation Loc, SourceLocation EndLoc, - ObligationSource &Source) { - if (!Loc.isValid()) - return; - PresumedLoc Location = SourceMgr.getPresumedLoc(Loc); - if (!Location.isValid()) - return; - ObligationSource Found; - Found.File = Location.getFilename(); - Found.Line = Location.getLine(); - Found.Column = Location.getColumn(); - PresumedLoc End = - SourceMgr.getPresumedLoc(EndLoc.isValid() ? EndLoc : Loc); - if (End.isValid() && Found.File == End.getFilename() && - (End.getLine() > Found.Line || - (End.getLine() == Found.Line && End.getColumn() >= Found.Column))) { - Found.EndLine = End.getLine(); - Found.EndColumn = End.getColumn(); - } else { - Found.EndLine = Found.Line; - Found.EndColumn = Found.Column; + ObligationSource Found; + if (!Loc.isValid()) + return Found; + PresumedLoc Location = SourceMgr.getPresumedLoc(Loc); + if (!Location.isValid()) + return Found; + Found.File = Location.getFilename(); + Found.Line = Location.getLine(); + Found.Column = Location.getColumn(); + auto inFile = [&](const PresumedLoc &At) { + return At.isValid() && Found.File == At.getFilename(); + }; + auto before = [](unsigned Line, unsigned Column, unsigned OtherLine, + unsigned OtherColumn) { + return Line < OtherLine || (Line == OtherLine && Column < OtherColumn); + }; + SourceLocation Last = EndLoc.isValid() ? EndLoc : Loc; + if (Last.isMacroID()) + Last = SourceMgr.getExpansionRange(Last).getEnd(); + SourceLocation After = + Lexer::getLocForEndOfToken(Last, 0, SourceMgr, Ctx.getLangOpts()); + PresumedLoc End = SourceMgr.getPresumedLoc(After.isValid() ? After : Last); + if (inFile(End) && + !before(End.getLine(), End.getColumn(), Found.Line, Found.Column)) { + Found.EndLine = End.getLine(); + Found.EndColumn = End.getColumn(); + } else { + Found.EndLine = Found.Line; + Found.EndColumn = Found.Column; + } + if (BeginLoc.isValid()) { + if (BeginLoc.isMacroID()) + BeginLoc = SourceMgr.getExpansionRange(BeginLoc).getBegin(); + PresumedLoc Begin = SourceMgr.getPresumedLoc(BeginLoc); + if (inFile(Begin) && before(Begin.getLine(), Begin.getColumn(), + Found.Line, Found.Column)) { + Found.BeginLine = Begin.getLine(); + Found.BeginColumn = Begin.getColumn(); } + } + return Found; + } + + void annotateObligationSources(ObligationModule &Module) { + auto annotateSource = [&](SourceLocation Loc, SourceLocation BeginLoc, + SourceLocation EndLoc, ObligationSource &Source) { + ObligationSource Found = sourceOf(Loc, BeginLoc, EndLoc); + if (!Found.isValid()) + return; // A term shared with a module annotated before, which other threads // may be reading, is read and not written. if (Source.File != Found.File || Source.Line != Found.Line || Source.Column != Found.Column || Source.EndLine != Found.EndLine || - Source.EndColumn != Found.EndColumn) + Source.EndColumn != Found.EndColumn || + Source.BeginLine != Found.BeginLine || + Source.BeginColumn != Found.BeginColumn) Source = std::move(Found); }; // Terms share subterms: each node once. @@ -3003,7 +3021,7 @@ class Verifier { Pending.pop_back(); if (!Annotated.insert(Expr).second) continue; - annotateSource(Expr->Loc, Expr->EndLoc, Expr->Source); + annotateSource(Expr->Loc, Expr->BeginLoc, Expr->EndLoc, Expr->Source); for (const auto &Child : Expr->Children) if (Child) Pending.push_back(Child.get()); @@ -3014,7 +3032,7 @@ class Verifier { annotateExpr(Module.CounterexampleQuery.get()); std::map StableIdCounts; for (Obligation &Item : Module.Obligations) { - annotateSource(Item.Loc, Item.EndLoc, Item.Source); + annotateSource(Item.Loc, Item.BeginLoc, Item.EndLoc, Item.Source); std::string StableId = Module.FunctionIdentity + "::" + obligationKindName(Item.Kind) + "@"; StableId += Item.Source.isValid() @@ -3030,10 +3048,11 @@ class Verifier { } for (auto &[InternalName, Variable] : Module.DiagnosticVariables) { (void)InternalName; - annotateSource(Variable.Loc, Variable.EndLoc, Variable.Source); + annotateSource(Variable.Loc, Variable.Loc, Variable.EndLoc, + Variable.Source); } for (DiagnosticTraceEvent &Event : Module.TraceEvents) { - annotateSource(Event.Loc, Event.EndLoc, Event.Source); + annotateSource(Event.Loc, Event.Loc, Event.EndLoc, Event.Source); annotateExpr(Event.Guard.get()); for (DiagnosticTraceValue &Value : Event.Values) annotateExpr(Value.Value.get()); @@ -3252,6 +3271,7 @@ class Verifier { OutsideFunctions = true; else D.FunctionName = Err.FunctionName; + D.FunctionLoc = Err.FunctionLoc; D.Hidden = !Err.Function.empty() && !selects(Err.FunctionName); if (!Err.Function.empty() && UnsupportedConstructs.emplace(Err.Function, Err.Message).second) { @@ -6065,7 +6085,7 @@ class Verifier { void printJSONDiagnostic(const VerifyDiagnostic &D, llvm::raw_ostream &OS) const { llvm::json::Object Record; - Record["schema"] = "cppverify.diagnostic/1"; + Record["schema"] = "cppverify.diagnostic/2"; Record["status"] = D.Result ? verifyStatusCode(D.Result->Status) : diagnosticKindCode(D.K); Record["severity"] = @@ -6089,36 +6109,22 @@ class Verifier { ObligationSource Source; if (D.Result) Source = D.Result->Source; - if (!Source.isValid() && D.Loc.isValid()) { - PresumedLoc Location = Ctx.getSourceManager().getPresumedLoc(D.Loc); - if (Location.isValid()) { - Source.File = Location.getFilename(); - Source.Line = Location.getLine(); - Source.Column = Location.getColumn(); - Source.EndLine = Source.Line; - Source.EndColumn = Source.Column; - if (D.Span.isValid()) - if (PresumedLoc End = - Ctx.getSourceManager().getPresumedLoc(D.Span.getEnd()); - End.isValid()) { - Source.EndLine = End.getLine(); - Source.EndColumn = End.getColumn(); - } - } - } + if (!Source.isValid()) + Source = D.Span.isValid() + ? sourceOf(D.Loc, D.Span.getBegin(), D.Span.getEnd()) + : sourceOf(D.Loc, D.Loc, D.Loc); if (Source.isValid()) Record["source"] = sourceJSON(Source); + if (ObligationSource Function = + sourceOf(D.FunctionLoc, D.FunctionLoc, D.FunctionLoc); + Function.isValid()) + Record["function_source"] = sourceJSON(Function); if (const std::pair *Instantiation = instantiationOf(D)) - if (PresumedLoc Point = - Ctx.getSourceManager().getPresumedLoc(Instantiation->first); - Point.isValid()) { - ObligationSource At; - At.File = Point.getFilename(); - At.Line = At.EndLine = Point.getLine(); - At.Column = At.EndColumn = Point.getColumn(); + if (ObligationSource At = sourceOf( + Instantiation->first, Instantiation->first, Instantiation->first); + At.isValid()) Record["instantiated_at"] = sourceJSON(At); - } if (D.Vacuous) Record["vacuous"] = true; @@ -6232,6 +6238,9 @@ class Verifier { Obligation["source"] = sourceJSON(Result.Source); Record["obligation"] = std::move(Obligation); } + if (Result.Status == VerifyStatus::Failed) + if (std::string Values = counterexampleText(Result); !Values.empty()) + Record["counterexample"] = jsonText(Values); if (!Result.Model.empty()) { llvm::json::Array Model; for (const VerifyModelValue &Value : Result.Model) { @@ -6256,6 +6265,7 @@ class Verifier { llvm::json::Object Entry; Entry["kind"] = traceKindCode(Event.Kind); Entry["message"] = jsonText(Event.Message); + Entry["text"] = jsonText(traceStepText(Event)); Entry["active"] = Event.Active ? llvm::json::Value(*Event.Active) : llvm::json::Value(nullptr); if (Event.Source.isValid()) @@ -6712,6 +6722,37 @@ class Verifier { return Parts; } + /// A GitHub workflow command that annotates the source of an error or a + /// warning, or nothing for another result. + std::string githubAnnotation(const VerifyDiagnostic &D) const { + const bool Error = D.K == VerifyDiagnostic::Error || + D.K == VerifyDiagnostic::Unresolved || + D.K == VerifyDiagnostic::Interrupted; + if (!Error && D.K != VerifyDiagnostic::Warning && + D.K != VerifyDiagnostic::BoundedSafe) + return ""; + ObligationSource Source; + if (D.Result) + Source = D.Result->Source; + if (!Source.isValid()) + Source = sourceOf(D.Loc.isValid() ? D.Loc : D.FunctionLoc, + D.Span.getBegin(), D.Span.getEnd()); + std::string Message = statusLine(D); + if (D.Result && D.Result->Status == VerifyStatus::Failed) + if (std::string Values = counterexampleText(*D.Result); !Values.empty()) + Message += "\ncounterexample: " + Values; + for (const std::string &Note : D.Notes) + Message += "\n" + Note; + std::string Title = "cpp-verify"; + if (D.K == VerifyDiagnostic::Unresolved && D.Result) + Title += + ": unresolved (" + verifyReasonCode(D.Result->Reason).str() + ")"; + else if (D.Result && D.Result->ObligationType) + Title += + std::string(": ") + obligationKindName(*D.Result->ObligationType); + return githubCommand(Error ? "error" : "warning", Source, Title, Message); + } + /// Errors and warnings print as Clang prints its diagnostics, with the /// source they are about; other results as their status line. void printDiagnostic(const VerifyDiagnostic &D, llvm::raw_ostream &OS) const { @@ -6719,6 +6760,13 @@ class Verifier { printJSONDiagnostic(D, OS); return; } + printTextDiagnostic(D, OS); + if (Opts.Diagnostics == DiagnosticFormat::GitHub) + OS << githubAnnotation(D); + } + + void printTextDiagnostic(const VerifyDiagnostic &D, + llvm::raw_ostream &OS) const { const std::vector Parts = partsOf(D); if (D.K == VerifyDiagnostic::Error || D.K == VerifyDiagnostic::Warning) { DiagnosticOptions DiagOpts; From 47a7e0c1c6234f781e563105a41ac44ffcdc1a73 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:36 +0530 Subject: [PATCH 180/259] verify: Add SARIF and GitHub output, compiler diagnostics as records, and a summary record. --- clang/tools/cpp-verify/Main.cpp | 343 +++++++++++++++++++++++++++----- 1 file changed, 289 insertions(+), 54 deletions(-) diff --git a/clang/tools/cpp-verify/Main.cpp b/clang/tools/cpp-verify/Main.cpp index aeed96c9c3..adc4f01914 100644 --- a/clang/tools/cpp-verify/Main.cpp +++ b/clang/tools/cpp-verify/Main.cpp @@ -7,6 +7,7 @@ #include "Counterexample.h" #include "CppVerifyVersion.h" #include "DumpIR.h" +#include "StructuredOutput.h" #include "Verifier.h" #include "clang/AST/ASTConsumer.h" #include "clang/AST/ASTContext.h" @@ -14,6 +15,7 @@ #include "clang/Frontend/CompilerInvocation.h" #include "clang/Frontend/FrontendAction.h" #include "clang/Frontend/TextDiagnosticPrinter.h" +#include "clang/Lex/Lexer.h" #include "clang/Tooling/CommonOptionsParser.h" #include "clang/Tooling/Tooling.h" #include "llvm/ADT/STLExtras.h" @@ -259,13 +261,51 @@ static cl::opt ObligationIn( cl::desc("Validate and replay a backend-neutral obligation archive"), cl::value_desc("file"), cl::cat(CppVerifyCategory)); -static cl::opt DiagnosticsFormat( - "diagnostics-format", cl::desc("Verification diagnostics format"), - cl::values(clEnumValN(verify::DiagnosticFormat::Text, "text", - "Human-readable text (default)"), - clEnumValN(verify::DiagnosticFormat::Json, "json", - "Versioned JSON Lines")), - cl::init(verify::DiagnosticFormat::Text), cl::cat(CppVerifyCategory)); +enum class OutputFormat { Text, Json, Sarif, GitHub }; + +static cl::opt DiagnosticsFormat( + "diagnostics-format", cl::desc("Format of results and diagnostics"), + cl::values( + clEnumValN(OutputFormat::Text, "text", "Human-readable text (default)"), + clEnumValN(OutputFormat::Json, "json", + "JSON Lines (cppverify.diagnostic/2), ending with a " + "summary record"), + clEnumValN(OutputFormat::Sarif, "sarif", + "One SARIF 2.1.0 log at the end of the run"), + clEnumValN(OutputFormat::GitHub, "github", + "Text, with a GitHub workflow annotation for each error and " + "warning")), + cl::init(OutputFormat::Text), cl::cat(CppVerifyCategory)); + +/// Whether results are records: JSON Lines, or the SARIF made of them. +static bool structuredOutput() { + return DiagnosticsFormat == OutputFormat::Json || + DiagnosticsFormat == OutputFormat::Sarif; +} + +static verify::DiagnosticFormat verifierFormat() { + switch (DiagnosticsFormat) { + case OutputFormat::Text: + return verify::DiagnosticFormat::Text; + case OutputFormat::Json: + case OutputFormat::Sarif: + return verify::DiagnosticFormat::Json; + case OutputFormat::GitHub: + return verify::DiagnosticFormat::GitHub; + } + return verify::DiagnosticFormat::Text; +} + +// In SARIF mode the records are collected here and translated at the end. +static std::string gRecords; +static llvm::raw_string_ostream gRecordStream(gRecords); + +/// Where results go: standard output, or the records of a SARIF log. +static llvm::raw_ostream &out() { + if (DiagnosticsFormat == OutputFormat::Sarif) + return gRecordStream; + return llvm::outs(); +} static cl::opt Quiet("quiet", @@ -367,6 +407,51 @@ static void printSummary(std::chrono::steady_clock::time_point Start) { : llvm::join(Parts, ", ")) << llvm::formatv(" in {0:f1} s", Seconds) << "\n"; } +/// The summary as a record: the counts of the text line, by name. It has no +/// time, so that records do not depend on the run; --time-report gives it. +static void printSummaryRecord() { + llvm::json::Object Record; + Record["schema"] = verify::SummarySchema; + Record["verified"] = gSummary.Verified; + Record["failed"] = gSummary.Failed; + Record["unresolved"] = gSummary.Unresolved; + llvm::json::Object Reasons; + for (const auto &[Reason, N] : gSummary.Reasons) + Reasons[Reason] = N; + Record["reasons"] = std::move(Reasons); + Record["bounded_safe"] = gSummary.BoundedSafe; + Record["trusted"] = gSummary.Trusted; + Record["lowered"] = gSummary.Lowered; + Record["exported"] = gSummary.Exported; + Record["interrupted"] = gSummary.Interrupted; + out() << llvm::formatv("{0}\n", llvm::json::Value(std::move(Record))); +} + +static std::vector gArguments; + +/// Ends the run's output: in SARIF mode, the log of the records collected. +static int finishOutput(int ExitCode) { + if (DiagnosticsFormat != OutputFormat::Sarif) + return ExitCode; + gRecordStream.flush(); + std::vector Records; + for (llvm::StringRef Line : llvm::split(gRecords, '\n')) { + if (Line.trim().empty()) + continue; + if (llvm::Expected Record = llvm::json::parse(Line)) + Records.push_back(std::move(*Record)); + else + llvm::consumeError(Record.takeError()); + } + verify::SarifInvocation Invocation; + Invocation.Version = verify::releaseVersion().str(); + Invocation.Arguments = gArguments; + Invocation.ExitCode = ExitCode; + llvm::outs() << llvm::formatv("{0:2}\n", + verify::sarifLog(Records, Invocation)); + return ExitCode; +} + static llvm::raw_ostream *gObligationOut = nullptr; static uint64_t proofCacheMaxBytes() { @@ -442,9 +527,13 @@ static void setLeanOptions(verify::VerifyOptions &VOpts) { VOpts.LeanJobs = Jobs.getNumOccurrences() ? Jobs.getValue() : 0; } +static void flushFrontendRecords(); + class VerifyConsumer : public ASTConsumer { public: void HandleTranslationUnit(ASTContext &Ctx) override { + // The compiler's records come before the verifier's. + flushFrontendRecords(); if (!Ctx.getDiagnostics().getClient()->getNumErrors()) { verify::VerifyOptions VOpts; if (DumpIR.getNumOccurrences() > 0) @@ -480,7 +569,7 @@ class VerifyConsumer : public ASTConsumer { VOpts.ProofCacheMaxEntries = ProofCacheMaxEntries.getValue(); VOpts.CheckUB = CheckUB.getValue() && !NoCheckUB.getValue(); VOpts.ProfileQuantifiers = ProfileQuantifiers.getValue(); - VOpts.Diagnostics = DiagnosticsFormat.getValue(); + VOpts.Diagnostics = verifierFormat(); VOpts.ObligationOut = gObligationOut; VOpts.Quiet = Quiet.getValue(); VOpts.Verbose = Verbose.getValue(); @@ -495,7 +584,7 @@ class VerifyConsumer : public ASTConsumer { VOpts.ConfirmBound = ConfirmBound.getValue(); VOpts.Summary = &gSummary; VOpts.CrossFile = gCrossFile.get(); - if (!verify::verifyTranslationUnit(Ctx, llvm::outs(), VOpts)) + if (!verify::verifyTranslationUnit(Ctx, out(), VOpts)) ++gVerifyFailures; } } @@ -510,12 +599,141 @@ class VerifyAction : public ASTFrontendAction { } }; +/// The compiler's diagnostics as the run's format takes them: records of +/// status "frontend" in JSON and SARIF, each with the notes that follow it as +/// related locations; and in GitHub mode the text, with an annotation after +/// each error and warning. +class StructuredDiagnostics : public DiagnosticConsumer { +public: + explicit StructuredDiagnostics(DiagnosticConsumer *Text) : Text(Text) {} + ~StructuredDiagnostics() override { flush(); } + + void BeginSourceFile(const LangOptions &LangOpts, + const Preprocessor *PP) override { + if (Text) + Text->BeginSourceFile(LangOpts, PP); + } + void EndSourceFile() override { + flush(); + if (Text) + Text->EndSourceFile(); + } + /// Writes the record still waiting for its notes. + void finish() { flush(); } + + void HandleDiagnostic(DiagnosticsEngine::Level Level, + const Diagnostic &Info) override { + DiagnosticConsumer::HandleDiagnostic(Level, Info); + if (Level == DiagnosticsEngine::Ignored) + return; + llvm::SmallString<256> Message; + Info.FormatDiagnostic(Message); + verify::ObligationSource Source = sourceOf(Info); + if (Text) { + Text->HandleDiagnostic(Level, Info); + if (Level >= DiagnosticsEngine::Warning) + llvm::outs() << verify::githubCommand( + Level == DiagnosticsEngine::Warning ? "warning" : "error", Source, + "clang", Message); + return; + } + if (Level == DiagnosticsEngine::Note && Pending) { + llvm::json::Object Note; + Note["message"] = verify::jsonText(Message); + if (Source.isValid()) + Note["source"] = verify::sourceJSON(Source); + Related.push_back(std::move(Note)); + return; + } + flush(); + llvm::json::Object Record; + Record["schema"] = verify::DiagnosticSchema; + Record["status"] = "frontend"; + Record["severity"] = Level == DiagnosticsEngine::Remark ? "remark" + : Level == DiagnosticsEngine::Note ? "note" + : Level == DiagnosticsEngine::Warning ? "warning" + : "error"; + Record["message"] = verify::jsonText(Message); + llvm::StringRef Option = + Info.getDiags()->getDiagnosticIDs()->getWarningOptionForDiag( + Info.getID()); + if (!Option.empty()) + Record["option"] = ("-W" + Option).str(); + if (Source.isValid()) + Record["source"] = verify::sourceJSON(Source); + Pending = std::move(Record); + } + +private: + void flush() { + if (!Pending) + return; + if (!Related.empty()) + (*Pending)["related"] = std::move(Related); + out() << llvm::formatv("{0}\n", llvm::json::Value(std::move(*Pending))); + Pending.reset(); + Related = llvm::json::Array(); + } + + /// The diagnostic's source: its location, through its first range. + static verify::ObligationSource sourceOf(const Diagnostic &Info) { + verify::ObligationSource Source; + if (!Info.hasSourceManager() || Info.getLocation().isInvalid()) + return Source; + const SourceManager &SM = Info.getSourceManager(); + PresumedLoc At = SM.getPresumedLoc(Info.getLocation()); + if (!At.isValid()) + return Source; + Source.File = At.getFilename(); + Source.Line = Source.EndLine = At.getLine(); + Source.Column = Source.EndColumn = At.getColumn(); + if (Info.getNumRanges() == 0) + return Source; + CharSourceRange Range = Info.getRange(0); + SourceLocation Begin = SM.getExpansionLoc(Range.getBegin()); + SourceLocation End = SM.getExpansionLoc(Range.getEnd()); + if (Range.isTokenRange()) + End = Lexer::getLocForEndOfToken(End, 0, SM, LangOptions()); + PresumedLoc First = SM.getPresumedLoc(Begin); + PresumedLoc Last = SM.getPresumedLoc(End); + if (First.isValid() && Last.isValid() && + llvm::StringRef(First.getFilename()) == Source.File && + llvm::StringRef(Last.getFilename()) == Source.File) { + if (First.getLine() < Source.Line || + (First.getLine() == Source.Line && + First.getColumn() < Source.Column)) { + Source.BeginLine = First.getLine(); + Source.BeginColumn = First.getColumn(); + } + if (Last.getLine() > Source.Line || + (Last.getLine() == Source.Line && Last.getColumn() > Source.Column)) { + Source.EndLine = Last.getLine(); + Source.EndColumn = Last.getColumn(); + } + } + return Source; + } + + DiagnosticConsumer *Text; + std::optional Pending; + llvm::json::Array Related; +}; + +static StructuredDiagnostics *gStructured = nullptr; + +static void flushFrontendRecords() { + if (gStructured) + gStructured->finish(); +} + /// Verifies each file whose command line clang accepts. An argument error /// stops the file, as it stops clang; tooling would print it and go on. +/// Files report to Files when it is set, else with their own options. class VerifyActionFactory : public FrontendActionFactory { public: - explicit VerifyActionFactory(const DiagnosticConsumer &Arguments) - : Arguments(Arguments) {} + VerifyActionFactory(const DiagnosticConsumer &Arguments, + DiagnosticConsumer *Files) + : Arguments(Arguments), Files(Files) {} std::unique_ptr create() override { return std::make_unique(); } @@ -530,13 +748,13 @@ class VerifyActionFactory : public FrontendActionFactory { ArgumentErrors = Arguments.getNumErrors(); return false; } - // The file reports with its own diagnostic options. return FrontendActionFactory::runInvocation( - std::move(Invocation), Files, std::move(PCHContainerOps), nullptr); + std::move(Invocation), Files, std::move(PCHContainerOps), this->Files); } private: const DiagnosticConsumer &Arguments; + DiagnosticConsumer *Files; unsigned ArgumentErrors = 0; }; @@ -567,30 +785,15 @@ static llvm::StringRef replayStatusCode(verify::VerifyStatus Status) { return "unresolved"; } -static std::string jsonText(llvm::StringRef Text) { - return llvm::json::isUTF8(Text) ? Text.str() : llvm::json::fixUTF8(Text); -} - -static llvm::json::Object -replaySourceJSON(const verify::ObligationSource &Source) { - llvm::json::Object Result; - if (!Source.isValid()) - return Result; - Result["file"] = jsonText(Source.File); - Result["line"] = Source.Line; - Result["column"] = Source.Column; - Result["end_line"] = Source.EndLine != 0 ? Source.EndLine : Source.Line; - Result["end_column"] = - Source.EndColumn != 0 ? Source.EndColumn : Source.Column; - return Result; -} +using verify::jsonText; +using verify::sourceJSON; static void printReplayJSON(const verify::ObligationModule &Module, const verify::VerifyResult &Result, llvm::StringRef SemanticHash, unsigned LeanAutomatic) { llvm::json::Object Record; - Record["schema"] = "cppverify.diagnostic/1"; + Record["schema"] = verify::DiagnosticSchema; Record["status"] = replayStatusCode(Result.Status); Record["severity"] = Result.Status == verify::VerifyStatus::BoundedSafe ? "warning" @@ -599,9 +802,21 @@ static void printReplayJSON(const verify::ObligationModule &Module, ? "error" : "note"; Record["function"] = jsonText(Module.FunctionName); - Record["message"] = Result.Status == verify::VerifyStatus::Verified - ? ReplayProofNote - : jsonText(Result.Message); + std::string Message = Result.Message; + if (Result.Status == verify::VerifyStatus::Verified) { + Message = ReplayProofNote; + } else if (Result.Status == verify::VerifyStatus::Failed) { + Message = "verification failed: " + Module.FunctionName; + if (Result.ObligationType) + Message += std::string(" [") + + verify::obligationKindName(*Result.ObligationType) + "]"; + if (!Result.Message.empty()) + Message += " (" + Result.Message + ")"; + if (std::string Values = verify::counterexampleText(Result); + !Values.empty()) + Record["counterexample"] = jsonText(Values); + } + Record["message"] = jsonText(Message); Record["semantic_hash"] = ("sha256:" + SemanticHash).str(); if (!Result.BackendName.empty()) Record["backend"] = Result.BackendName; @@ -629,14 +844,14 @@ static void printReplayJSON(const verify::ObligationModule &Module, if (!Result.CacheError.empty()) Record["cache_error"] = jsonText(Result.CacheError); if (Result.Source.isValid()) - Record["source"] = replaySourceJSON(Result.Source); + Record["source"] = sourceJSON(Result.Source); if (!Result.ObligationId.empty()) { llvm::json::Object Obligation; Obligation["id"] = jsonText(Result.ObligationId); if (Result.ObligationType) Obligation["kind"] = verify::obligationKindName(*Result.ObligationType); if (Result.Source.isValid()) - Obligation["source"] = replaySourceJSON(Result.Source); + Obligation["source"] = sourceJSON(Result.Source); Record["obligation"] = std::move(Obligation); } if (!Result.Model.empty()) { @@ -649,7 +864,9 @@ static void printReplayJSON(const verify::ObligationModule &Module, Entry["value"] = Value.Value ? llvm::json::Value(jsonText(*Value.Value)) : llvm::json::Value(nullptr); if (Value.Source.isValid()) - Entry["source"] = replaySourceJSON(Value.Source); + Entry["source"] = sourceJSON(Value.Source); + if (Value.OnPath == false) + Entry["on_path"] = false; Model.push_back(std::move(Entry)); } Record["model"] = std::move(Model); @@ -671,10 +888,11 @@ static void printReplayJSON(const verify::ObligationModule &Module, : "branch"; Entry["kind"] = Kind; Entry["message"] = jsonText(Event.Message); + Entry["text"] = jsonText(verify::traceStepText(Event)); Entry["active"] = Event.Active ? llvm::json::Value(*Event.Active) : llvm::json::Value(nullptr); if (Event.Source.isValid()) - Entry["source"] = replaySourceJSON(Event.Source); + Entry["source"] = sourceJSON(Event.Source); llvm::json::Array Values; for (const verify::VerifyTraceValue &Value : Event.Values) { llvm::json::Object Item; @@ -690,7 +908,7 @@ static void printReplayJSON(const verify::ObligationModule &Module, } Record["trace"] = std::move(Trace); } - llvm::outs() << llvm::formatv("{0}\n", llvm::json::Value(std::move(Record))); + out() << llvm::formatv("{0}\n", llvm::json::Value(std::move(Record))); } /// Selects the backend that the only backend an option applies to, when no @@ -901,17 +1119,16 @@ static int replayObligationArchive() { setLeanOptions(VOpts); Project = verify::replayLeanProject(Modules, VOpts); for (const std::string &Warning : Project->Warnings) { - if (DiagnosticsFormat != verify::DiagnosticFormat::Json) { + if (!structuredOutput()) { llvm::outs() << "warning: " << Warning << "\n"; continue; } llvm::json::Object Record; - Record["schema"] = "cppverify.diagnostic/1"; + Record["schema"] = verify::DiagnosticSchema; Record["status"] = "warning"; Record["severity"] = "warning"; Record["message"] = jsonText(Warning); - llvm::outs() << llvm::formatv("{0}\n", - llvm::json::Value(std::move(Record))); + out() << llvm::formatv("{0}\n", llvm::json::Value(std::move(Record))); } if (!Project->Error.empty()) { llvm::errs() << "error: " << Project->Error << "\n"; @@ -953,7 +1170,7 @@ static int replayObligationArchive() { } const std::string Hash = verify::obligationSemanticHash(Module); - if (DiagnosticsFormat == verify::DiagnosticFormat::Json) { + if (structuredOutput()) { printReplayJSON(Module, Result, Hash, LeanAutomatic); if (Result.Status != verify::VerifyStatus::Lowered && Result.Status != verify::VerifyStatus::Verified && @@ -1086,6 +1303,7 @@ static int replayObligationArchive() { int main(int argc, const char **argv) { const auto Start = std::chrono::steady_clock::now(); llvm::InitLLVM X(argc, argv); + gArguments.assign(argv, argv + argc); // The first Ctrl-C stops the solvers and reports what is not finished; a // second one ends the process. llvm::sys::SetInterruptFunction(verify::requestInterrupt); @@ -1145,7 +1363,7 @@ int main(int argc, const char **argv) { "source files\n"; return 1; } - return replayObligationArchive(); + return finishOutput(replayObligationArchive()); } std::unique_ptr ObligationFile; @@ -1206,27 +1424,44 @@ int main(int argc, const char **argv) { std::unique_ptr ArgumentOptions = CreateAndPopulateDiagOpts({"cpp-verify"}); TextDiagnosticPrinter ArgumentDiagnostics(llvm::errs(), *ArgumentOptions); - Tool.setDiagnosticConsumer(&ArgumentDiagnostics); - VerifyActionFactory Factory(ArgumentDiagnostics); + // Records and annotations need every file to report to one consumer. + std::optional Structured; + if (DiagnosticsFormat != OutputFormat::Text) + Structured.emplace(DiagnosticsFormat == OutputFormat::GitHub + ? &ArgumentDiagnostics + : nullptr); + gStructured = Structured ? &*Structured : nullptr; + DiagnosticConsumer &Arguments = + Structured ? static_cast(*Structured) + : ArgumentDiagnostics; + Tool.setDiagnosticConsumer(&Arguments); + VerifyActionFactory Factory(Arguments, Structured ? &*Structured : nullptr); // Lean exports and --list-functions have no verdicts to settle. if (OptionsParser.getSourcePathList().size() > 1 && BackendOpt != "lean" && LeanFallback.empty() && !ListFunctions) gCrossFile = std::make_unique(); int RC = Tool.run(&Factory); if (gCrossFile) - gVerifyFailures += gCrossFile->finish(llvm::outs(), &gSummary); - if (DiagnosticsFormat == verify::DiagnosticFormat::Text && !ListFunctions) - printSummary(Start); + gVerifyFailures += gCrossFile->finish(out(), &gSummary); + if (Structured) + Structured->finish(); + gStructured = nullptr; + if (!ListFunctions) { + if (structuredOutput()) + printSummaryRecord(); + else + printSummary(Start); + } if (verify::interruptRequested()) - return 130; + return finishOutput(130); if (RC != 0) - return RC; + return finishOutput(RC); if (ObligationFile) { ObligationFile->flush(); if (ObligationFile->has_error()) { llvm::errs() << "error: cannot write obligation archive\n"; - return 1; + return finishOutput(1); } } - return gVerifyFailures > 0 ? 1 : 0; + return finishOutput(gVerifyFailures > 0 ? 1 : 0); } From 3c9081d874a93eabf171b5128d6a4bbe31f2f202 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:36 +0530 Subject: [PATCH 181/259] test: Add the input of the structured output test. --- .../Verify/suite/Inputs/structured_output.cpp | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) create mode 100644 clang/test/Verify/suite/Inputs/structured_output.cpp diff --git a/clang/test/Verify/suite/Inputs/structured_output.cpp b/clang/test/Verify/suite/Inputs/structured_output.cpp new file mode 100644 index 0000000000..3759965f2e --- /dev/null +++ b/clang/test/Verify/suite/Inputs/structured_output.cpp @@ -0,0 +1,29 @@ +namespace cv = cppverify; + +int inc(int x) + cv::pre(x < 100) + cv::post(cv::result == x + 1) +{ + return x + 1; +} + +int clamp(int x) + cv::post(cv::result >= 0) +{ + if (x < 0) + return x + 1; + return x; +} + +int never(int x) + cv::pre(x > 0 && x < 0) + cv::post(cv::result == 1) +{ + return 0; +} + +int assigns(int x) { + if (x = 1) + return 0; + return 1; +} From 8f8970c8eac754546f642fabe6c2da9549345ea3 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:36 +0530 Subject: [PATCH 182/259] test: Add an input with a compiler error for the structured output test. --- clang/test/Verify/suite/Inputs/structured_syntax_error.cpp | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 clang/test/Verify/suite/Inputs/structured_syntax_error.cpp diff --git a/clang/test/Verify/suite/Inputs/structured_syntax_error.cpp b/clang/test/Verify/suite/Inputs/structured_syntax_error.cpp new file mode 100644 index 0000000000..51b76935ee --- /dev/null +++ b/clang/test/Verify/suite/Inputs/structured_syntax_error.cpp @@ -0,0 +1,5 @@ +int broken(int x) + cppverify::post(cppverify::result > 0) +{ + return x +} From 7b707422e8776f1927be7eae066e3276a3da1ba0 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:37 +0530 Subject: [PATCH 183/259] test: Check JSON v2, SARIF, and GitHub output. --- .../test/Verify/suite/structured_output.test | 105 ++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 clang/test/Verify/suite/structured_output.test diff --git a/clang/test/Verify/suite/structured_output.test b/clang/test/Verify/suite/structured_output.test new file mode 100644 index 0000000000..df1effe0b5 --- /dev/null +++ b/clang/test/Verify/suite/structured_output.test @@ -0,0 +1,105 @@ +# Results as records: JSON Lines of cppverify.diagnostic/2, ending with a +# cppverify.summary/1 record; one SARIF 2.1.0 log made of the same records; +# and, in GitHub mode, the text with a workflow annotation after each error and +# warning. The compiler's own diagnostics are records too. A record's source +# spans its expression, from its first column to the one after its last. +# +# RUN: not %cpp-verify --jobs=1 --diagnostics-format=json %S/Inputs/structured_output.cpp -- 2>/dev/null \ +# RUN: | FileCheck %s --check-prefix=JSON +# RUN: not %cpp-verify --jobs=1 --diagnostics-format=sarif %S/Inputs/structured_output.cpp -- 2>/dev/null \ +# RUN: | FileCheck %s --check-prefix=SARIF +# RUN: not %cpp-verify --diagnostics-format=json %S/Inputs/structured_syntax_error.cpp -- 2>/dev/null \ +# RUN: | FileCheck %s --check-prefix=FRONTEND +# RUN: not %cpp-verify --jobs=1 --obligation-out=%t.cpv %S/Inputs/structured_output.cpp -- > /dev/null 2>&1 +# RUN: not %cpp-verify --obligation-in=%t.cpv --diagnostics-format=sarif 2>/dev/null \ +# RUN: | FileCheck %s --check-prefix=REPLAY +# RUN: cd %S/Inputs && not %cpp-verify --jobs=1 --diagnostics-format=github structured_output.cpp -- 2>/dev/null \ +# RUN: | FileCheck %s --check-prefix=GITHUB + +The compiler's warning comes first, with its notes as related locations. +JSON: {"message":"using the result of an assignment as a condition without parentheses","option":"-Wparentheses","related":[{"message":"place parentheses around the assignment to silence this warning","source":{"column":9,"end_column":9,"end_line":26,"file":"{{.*}}structured_output.cpp","line":26}},{"message":"use '==' to turn this assignment into an equality comparison","source":{{.*}}}],"schema":"cppverify.diagnostic/2","severity":"warning","source":{"column":7,"end_column":12,"end_line":26,"file":"{{.*}}structured_output.cpp","line":26},"status":"frontend"} +Every result names its function and where it is declared. +JSON-NEXT: {"backend":"z3","function":"inc","function_source":{"column":5,"end_column":8,"end_line":3,"file":"{{.*}}structured_output.cpp","line":3},"message":"inc [backend=z3]","schema":"cppverify.diagnostic/2","severity":"note","status":"verified"} +A failure spans the expression it checks, and gives its counterexample and +the steps of its path as the text prints them. +JSON-NEXT: {"backend":"z3","counterexample":"x = {{-[0-9]+}}, result = {{-?[0-9]+}}","function":"clamp" +JSON-SAME: "obligation":{"id":"{{.*}}::postcondition@11:23","kind":"postcondition","source":{"column":12,"end_column":27,"end_line":11,"file":"{{.*}}structured_output.cpp","line":11}} +JSON-SAME: "source":{"column":12,"end_column":27,"end_line":11,"file":"{{.*}}structured_output.cpp","line":11},"status":"failed" +JSON-SAME: "text":"takes the true branch" +JSON-SAME: "text":"returns {{-?[0-9]+}}" +JSON-NEXT: "function":"never"{{.*}}"status":"verified","vacuous":true} +JSON-NEXT: {"function":"never","function_source":{"column":5,"end_column":10,"end_line":18,"file":"{{.*}}structured_output.cpp","line":18},"message":"never: the precondition is unsatisfiable, so every claim about it holds vacuously","schema":"cppverify.diagnostic/2","severity":"warning","status":"warning"} +The run ends with its counts. +JSON-NEXT: {"bounded_safe":0,"exported":0,"failed":1,"interrupted":0,"lowered":0,"reasons":{},"schema":"cppverify.summary/1","trusted":0,"unresolved":0,"verified":2} +JSON-NOT: {{.}} + +SARIF: "$schema": "https://docs.oasis-open.org/sarif/sarif/v2.1.0/errata01/os/schemas/sarif-schema-2.1.0.json", +SARIF: "uri": "file://{{.*}}/Inputs/structured_output.cpp" +SARIF: "executionSuccessful": true, +SARIF-NEXT: "exitCode": 1 +SARIF: "summary": { +SARIF: "failed": 1, +SARIF: "verified": 2 +SARIF: "results": [ +The compiler's warning, its notes as related locations. +SARIF: "kind": "fail", +SARIF-NEXT: "level": "warning", +SARIF: "text": "using the result of an assignment as a condition without parentheses" +SARIF: "option": "-Wparentheses", +SARIF: "relatedLocations": [ +SARIF: "text": "place parentheses around the assignment to silence this warning" +SARIF: "ruleId": "frontend", +A proof passes. +SARIF: "kind": "pass", +SARIF-NEXT: "level": "none", +SARIF: "name": "inc" +SARIF: "text": "Verified: inc [backend=z3]" +SARIF: "ruleId": "verified", +A failure fails, its path a code flow and its rule the kind of check. +SARIF: "codeFlows": [ +SARIF: "text": "takes the true branch" +SARIF: "startLine": 13 +SARIF: "text": "returns {{-?[0-9]+}}" +SARIF: "kind": "fail", +SARIF-NEXT: "level": "error", +SARIF: "endColumn": 27, +SARIF-NEXT: "endLine": 11, +SARIF-NEXT: "startColumn": 12, +SARIF-NEXT: "startLine": 11 +SARIF: "text": "verification failed: clamp [postcondition] [backend=z3] [reason=counterexample]\ncounterexample: x = {{-[0-9]+}}, result = {{-?[0-9]+}}" +SARIF: "obligation": "{{.*}}::postcondition@11:23", +SARIF: "ruleId": "postcondition", +SARIF: "text": "Verified: never [backend=z3] [vacuous]" +A warning of the verifier. +SARIF: "kind": "fail", +SARIF-NEXT: "level": "warning", +SARIF: "ruleId": "warning", +SARIF: "tool": { +SARIF: "name": "cpp-verify", +SARIF: "rules": [ +SARIF: "id": "frontend", +SARIF: "id": "verified", +SARIF: "level": "error" +SARIF-NEXT: }, +SARIF: "id": "postcondition", +SARIF: "version": "2.1.0" + +A compiler error is a record of its own, and nothing is verified. +FRONTEND: {"message":"expected ';' after return statement","schema":"cppverify.diagnostic/2","severity":"error","source":{"column":11,"end_column":11,"end_line":4,"file":"{{.*}}structured_syntax_error.cpp","line":4},"status":"frontend"} +FRONTEND-NEXT: {{.*}}"failed":0,{{.*}}"schema":"cppverify.summary/1",{{.*}}"verified":0} + +An archive keeps the range a failure spans. +REPLAY: "kind": "fail", +REPLAY-NEXT: "level": "error", +REPLAY: "endColumn": 27, +REPLAY-NEXT: "endLine": 11, +REPLAY-NEXT: "startColumn": 12, +REPLAY-NEXT: "startLine": 11 +REPLAY: "ruleId": "postcondition", + +GitHub's annotations name files relative to the working directory. +GITHUB: ::warning file=structured_output.cpp,line=26,col=7,endLine=26,endColumn=12,title=clang::using the result of an assignment as a condition without parentheses +GITHUB: Verified: inc [backend=z3] +GITHUB: ::error file=structured_output.cpp,line=11,col=12,endLine=11,endColumn=27,title=cpp-verify%3A postcondition::verification failed: clamp [postcondition] [backend=z3] [reason=counterexample]%0Acounterexample: x = {{-[0-9]+}}, result = {{-?[0-9]+}} +GITHUB: ::warning file=structured_output.cpp,line=18,col=5,endLine=18,endColumn=10,title=cpp-verify::never: the precondition is unsatisfiable, so every claim about it holds vacuously +GITHUB: Summary: 2 verified, 1 failed From 37219ef95f1067142860b5826991c21ac319af74 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:37 +0530 Subject: [PATCH 184/259] test: Read archive schema v5 and write records of schema v4. --- .../suite/Inputs/mutate_obligation_archive.py | 39 ++++++++++++++++--- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/clang/test/Verify/suite/Inputs/mutate_obligation_archive.py b/clang/test/Verify/suite/Inputs/mutate_obligation_archive.py index 9227cec37b..90820f341e 100644 --- a/clang/test/Verify/suite/Inputs/mutate_obligation_archive.py +++ b/clang/test/Verify/suite/Inputs/mutate_obligation_archive.py @@ -25,6 +25,8 @@ def __init__(self, data): self.measures = [] # What schema 4 adds: where each diagnostic variable is defined. self.guard_spans = [] + # What schema 5 adds: the begin of each source range. + self.begin_spans = [] self.modules = [] def u8(self): @@ -77,6 +79,11 @@ def source(self): end_line = self.u32() end_column_offset = self.offset end_column = self.u32() + if self.version >= 5: + start = self.offset + self.u32() + self.u32() + self.begin_spans.append((start, self.offset)) result = { "line": line, "line_offset": line_offset, @@ -376,6 +383,8 @@ def invalidate_quantifier_binder_sort(self, node): "schema-v1-kinds", "schema-v2", "schema-v3", + "schema-v4", + "invalid-source-begin", "invalid-guard-flag", "measure-free-variable", "truncated", @@ -391,11 +400,21 @@ def invalidate_quantifier_binder_sort(self, node): if args.mode == "invalid-kind": archive.data[archive.expression_kind_offsets[0]] = 255 -elif args.mode == "schema-v3": +elif args.mode in ("schema-v3", "schema-v4"): + version = 3 if args.mode == "schema-v3" else 4 for offset in archive.version_offsets: - struct.pack_into(" Date: Wed, 28 Oct 2026 04:24:38 +0530 Subject: [PATCH 185/259] test: Read cppverify.diagnostic/2 records and the summary record in the fidelity gate. --- clang/test/Verify/suite/Inputs/run_backend_fidelity.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/Inputs/run_backend_fidelity.py b/clang/test/Verify/suite/Inputs/run_backend_fidelity.py index cbbbdf3871..903c52aad2 100644 --- a/clang/test/Verify/suite/Inputs/run_backend_fidelity.py +++ b/clang/test/Verify/suite/Inputs/run_backend_fidelity.py @@ -124,7 +124,10 @@ def parse_json_lines(output): fail("non-JSON diagnostic on line {}: {} ({})".format( line_number, line, error )) - if record.get("schema") != "cppverify.diagnostic/1": + # The run's counts end the stream. + if record.get("schema") == "cppverify.summary/1": + continue + if record.get("schema") != "cppverify.diagnostic/2": fail("unexpected diagnostic schema: {}".format(record)) records.append(record) if not records: From cb789e20a9ac736da0a9393c34e78ef999444925 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:38 +0530 Subject: [PATCH 186/259] test: Replay archive schema v4 and reject a range that begins after its anchor. --- clang/test/Verify/suite/obligation_archive.test | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/obligation_archive.test b/clang/test/Verify/suite/obligation_archive.test index e22bdbaab1..ae6860096b 100644 --- a/clang/test/Verify/suite/obligation_archive.test +++ b/clang/test/Verify/suite/obligation_archive.test @@ -15,7 +15,7 @@ # RUN: %python %S/Inputs/mutate_obligation_archive.py truncated %t.one %t.truncated # RUN: not %cpp-verify --obligation-in=%t.truncated 2>&1 | FileCheck %s --check-prefix=TRUNCATED # RUN: cp %t.one %t.version -# RUN: printf '\005\000\000\000' | dd of=%t.version bs=1 seek=8 conv=notrunc 2>/dev/null +# RUN: printf '\006\000\000\000' | dd of=%t.version bs=1 seek=8 conv=notrunc 2>/dev/null # RUN: not %cpp-verify --obligation-in=%t.version 2>&1 | FileCheck %s --check-prefix=VERSION # RUN: %python %S/Inputs/mutate_obligation_archive.py schema-v1 %t.one %t.schema-v1 # RUN: not %cpp-verify --obligation-in=%t.schema-v1 2>&1 | FileCheck %s --check-prefix=SCHEMA-V1 @@ -25,6 +25,10 @@ # RUN: %cpp-verify --obligation-in=%t.schema-v2 --backend=z3 | FileCheck %s --check-prefix=SCHEMA-V2 # RUN: %python %S/Inputs/mutate_obligation_archive.py schema-v3 %t.one %t.schema-v3 # RUN: %cpp-verify --obligation-in=%t.schema-v3 --backend=z3 | FileCheck %s --check-prefix=SCHEMA-V3 +# RUN: %python %S/Inputs/mutate_obligation_archive.py schema-v4 %t.one %t.schema-v4 +# RUN: %cpp-verify --obligation-in=%t.schema-v4 --backend=z3 | FileCheck %s --check-prefix=SCHEMA-V3 +# RUN: %python %S/Inputs/mutate_obligation_archive.py invalid-source-begin %t.one %t.source-begin +# RUN: not %cpp-verify --obligation-in=%t.source-begin 2>&1 | FileCheck %s --check-prefix=SOURCE-BEGIN # RUN: %python %S/Inputs/mutate_obligation_archive.py invalid-guard-flag %t.one %t.guard-flag # RUN: not %cpp-verify --obligation-in=%t.guard-flag 2>&1 | FileCheck %s --check-prefix=GUARD-FLAG # A measure is read like a definition, over the function's parameters. @@ -103,7 +107,7 @@ # REPLAY: Proved obligations: canonical_obligations (dependencies not checked in replay) [backend=z3] [semantic-hash=sha256:{{[0-9a-f]+}}] # LOWER: vc canonical_obligations -# LOWER: schema cppverify.obligation/4 +# LOWER: schema cppverify.obligation/5 # LOWER: (let # LOWER: Lowered: canonical_obligations [backend=z3] [semantic-hash=sha256:{{[0-9a-f]+}}] # LEAN: Exported: lean obligation: canonical_obligations [backend=lean] @@ -117,6 +121,7 @@ # SCHEMA-V2: Proved obligations: canonical_obligations (dependencies not checked in replay) [backend=z3] # SCHEMA-V3: Proved obligations: canonical_obligations (dependencies not checked in replay) [backend=z3] # GUARD-FLAG: error: invalid obligation archive: invalid diagnostic variable guard in obligation archive +# SOURCE-BEGIN: error: invalid obligation archive: source range begins after its anchor # MEASURE: error: invalid obligation archive: logical function definition has a free variable: z # KIND: error: invalid obligation archive: invalid expression kind in obligation archive # FEATURES: error: invalid obligation archive: obligation archive feature declaration does not match contents From 8fb55d55b6a3aca2a7de46b3cc7497ff39362d8d Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:39 +0530 Subject: [PATCH 187/259] test: Expect archive schema v5 in obligation dumps. --- clang/test/Verify/suite/obligation_ir.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/obligation_ir.cpp b/clang/test/Verify/suite/obligation_ir.cpp index 492a39b6c8..936e594f82 100644 --- a/clang/test/Verify/suite/obligation_ir.cpp +++ b/clang/test/Verify/suite/obligation_ir.cpp @@ -28,7 +28,7 @@ int canonical_obligations(int x) } // OBLIGATION-LABEL: vc canonical_obligations -// OBLIGATION-NEXT: schema cppverify.obligation/4 +// OBLIGATION-NEXT: schema cppverify.obligation/5 // OBLIGATION-NEXT: simplification nodes {{[1-9][0-9]*}} -> {{[1-9][0-9]*}}, rewrites {{[1-9][0-9]*}}, functions-removed 0 // OBLIGATION-NEXT: semantic-hash sha256:f6d09cd4e2ac5c541fa8e0e443f4c2981e5763ce9b4d94d69f9856eaa1e95f2e // OBLIGATION-NEXT: identity [[IDENTITY:fn_[0-9a-f]+]] From 83f4b038d1cb891c17bb7a5e34005d006793b02c Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:39 +0530 Subject: [PATCH 188/259] docs: Name SARIF output in the README. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index d13891a5e4..e0572ddae0 100644 --- a/README.md +++ b/README.md @@ -157,6 +157,7 @@ and `docs/UB-CHECKING.md`. ./build/bin/cpp-verify --timeout=10000 --solver-rlimit=2000000 file.cpp ./build/bin/cpp-verify --int-encoding=bitvector file.cpp # auto (default) | integer | bitvector ./build/bin/cpp-verify --diagnostics-format=json file.cpp # JSON Lines, for editors/CI +./build/bin/cpp-verify --diagnostics-format=sarif file.cpp # SARIF 2.1.0, for code scanning ./build/bin/cpp-verify --obligation-out=goals.cpv file.cpp # backend-neutral archive ./build/bin/cpp-verify --dump-ir=1,2,3,4 file.cpp # VCR, passive, Obligation IR, Z3 ``` From 43b5bdfbc2b4e0480e10a1a124a6b29bb80397f9 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:39 +0530 Subject: [PATCH 189/259] docs: Describe JSON v2, SARIF, GitHub output, and archive schema v5. --- docs/ARCHITECTURE.md | 34 ++++++++++++++++++++++++++++------ 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index d35c138a6e..98ef5abdae 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -68,7 +68,7 @@ C++ source with contracts │ - Source names + types │ │ - Guarded event traces │ │ - Stable reason codes │ -│ - Text or JSON Lines │ +│ - Text, JSON, SARIF │ │ - Re-check recommends │ │ on failure → warnings │ └──────────────────────────┘ @@ -1061,7 +1061,7 @@ and obligation kinds. ### Canonical archives and semantic identity `--obligation-out=FILE` writes one or more deterministic -`cppverify.obligation/4` records after source attribution. The binary format has +`cppverify.obligation/5` records after source attribution. The binary format has the `CPVOBL\r\n` magic, an explicit schema version, little-endian fixed-width integers, length-delimited strings/collections, and stable hand-assigned wire tags rather than C++ enum ordinals. The reader bounds strings, collections, @@ -1090,7 +1090,11 @@ premises, and schema v4, with the diagnostic metadata, where each variable version is defined (`DiagnosticVariable::Guard`); readers still read schemas v3, v2, and v1, whose records name only assertions, postconditions, and unwinding checks. A record before v4 gives no version a guard, so its -counterexamples list every version, as before 0.2. Records +counterexamples list every version, as before 0.2. Schema v5 adds, after each +source's end, the begin of its range (`ObligationSource::BeginLine`, +`BeginColumn`); from v5 the end is the column after the last character +(`Lexer::getLocForEndOfToken`), where before it was the first column of the +last token, and a record before v5 keeps its end as written. Records limit strings to 64 MiB, collections and expression nodes/edges to 100,000 per record, expression nesting to 4096, canonical integer numerals to 4096 decimal characters, and integer sorts to 4096 bits. @@ -2437,10 +2441,28 @@ tool prints errors and warnings with `TextDiagnostic`, source line and caret included, and verdicts as one line each; the compile path reports every part through the compiler's `DiagnosticsEngine` (see Compile-Time Integration). `--diagnostics-format=json` emits one -`cppverify.diagnostic/1` JSON object per verification result, including source +`cppverify.diagnostic/2` JSON object per verification result, including source ranges, typed model values, trace events, backend/bound, and a stable reason -code. Command-line/frontend errors and output combined with IR dumps are not a -pure JSON stream. A construct the converter cannot represent is a +code. A source (`ObligationSource`, annotated by `Verifier::sourceOf`) keeps +the anchor that stable IDs and carets use (`Line`, `Column`) and spans its +expression from `BeginLoc` to the end of its last token; records print the +span. Every record of a function carries its declaration +(`VerifyDiagnostic::FunctionLoc`, also for conversion errors through +`ConversionError::FunctionLoc`), and a failure the counterexample and step +texts the text output prints. In `cpp-verify` the compiler's diagnostics go to +`StructuredDiagnostics`, which writes them as records of status `frontend` +with their notes as `related`, before the verifier's records of the file, and +a `cppverify.summary/1` record ends the run. No record holds a time, so the +stream is the same at any `--jobs`. `--diagnostics-format=sarif` writes the +same records into a buffer (`out()` in `Main.cpp`) and translates them at the +end (`sarifLog`, `Driver/StructuredOutput.cpp`): a result per record, its +SARIF `kind` from the status as Frama-C maps property statuses (pass, fail, +open), its rule the failing check's kind, the trace a code flow, and the +summary a property of the run. The logs of `structured_output.test`, of +`inductive_counterexamples.cpp`, and of a replay validate against the SARIF +2.1.0 schema. `--diagnostics-format=github` is the text with a +workflow command (`githubCommand`) after each error and warning. Output +combined with IR dumps is not a pure JSON stream. A construct the converter cannot represent is a `ConversionError` at a source range: the innermost declaration, statement, or expression being converted (`ASTConverter::CurrentRange`), unless the site names a place of its own, such as a function for the checks made after every From 9acc1d17c8343d509688358eadf28c52cd8c0c51 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:40 +0530 Subject: [PATCH 190/259] docs: Note JSON v2, SARIF, and archive schema v5. --- docs/DESIGN.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/docs/DESIGN.md b/docs/DESIGN.md index a0c886149b..47acb4d459 100644 --- a/docs/DESIGN.md +++ b/docs/DESIGN.md @@ -2281,11 +2281,12 @@ dead declarations or trivial Boolean structure. It does not rewrite arithmetic, quantifiers, pointer/heap expressions, or assumptions. `--obligation-out=FILE` publishes deterministic, concatenable -`cppverify.obligation/4` binary records with stable wire tags and portable +`cppverify.obligation/5` binary records with stable wire tags and portable source attribution; schema v3 adds each logical function's termination measures and, with source attribution, where each assumption of a goal comes from, schema v4 where each variable version of a counterexample is defined, -none of them hashed, and records of schemas v1 to v3 remain readable. Publication includes an +schema v5 where each source range begins, none of them hashed, and records of +schemas v1 to v4 remain readable. Publication includes an exact serialize/deserialize/validate/reserialize check. SHA-256 module and per-obligation semantic hashes exclude source paths, display-only names, both positional and source-anchored obligation IDs, and every obligation kind except @@ -2328,9 +2329,12 @@ their human message: `counterexample`, `solver.timeout`, `solver.unknown`, `spec.reads`, `spec.post`, `spec.inductive`, `proof.cycle`, `counterexample.unchecked`, `construct.unsupported`, `callee.contract`, `decreases.missing`, and `interrupted`. -`--diagnostics-format=json` serializes verification results as versioned JSON -Lines (`cppverify.diagnostic/1`) for both source verification and archive -replay. +`--diagnostics-format=json` serializes verification results and compiler +diagnostics as versioned JSON Lines (`cppverify.diagnostic/2`, ending with a +`cppverify.summary/1` record) for both source verification and archive +replay; `--diagnostics-format=sarif` translates the same records into one +SARIF 2.1.0 log, and `--diagnostics-format=github` adds a GitHub workflow +annotation to the text for each error and warning. `--jobs=N` runs one pool of exactly `N` workers (default: the available physical cores, or `CPPVERIFY_JOBS`; 1 for `--backend=lean` and for the From 2dfc81c719cf87597345260b99cac186ca49841f Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:40 +0530 Subject: [PATCH 191/259] docs: Document JSON v2, SARIF, and GitHub annotations. --- website/source/language/tooling.rst | 125 +++++++++++++++++++++------- 1 file changed, 97 insertions(+), 28 deletions(-) diff --git a/website/source/language/tooling.rst b/website/source/language/tooling.rst index e23d9bcdbf..0ed9338fc6 100644 --- a/website/source/language/tooling.rst +++ b/website/source/language/tooling.rst @@ -34,6 +34,8 @@ Standalone verifier cpp-verify --jobs=4 --proof-cache=.cppverify-cache file.cpp cpp-verify --solver-rlimit=500000 --max-query-nodes=50000 file.cpp cpp-verify --diagnostics-format=json file.cpp + cpp-verify --diagnostics-format=sarif file.cpp > results.sarif + cpp-verify --diagnostics-format=github file.cpp cpp-verify --dump-ir=1,2,3,4 file.cpp cpp-verify --lower-only --dump-ir=1,2,3,4 file.cpp cpp-verify --lower-only --obligation-out=goals.cpv file.cpp @@ -237,9 +239,9 @@ bounded-safe, trusted, lowered, exported, interrupted), gives the reasons of the unresolved ones (``2 unresolved (spec.fuel 1, solver.timeout 1)``), and the time the run took. A function the verifier does not represent counts as unresolved, ``construct.unsupported``. The summary covers every file of the -run, and is left out of ``--diagnostics-format=json``, whose records are the -whole output, of ``--list-functions``, and of archive replay -(``--obligation-in``), which prints a line per module. +run. In JSON it is the last record, and in SARIF a property of the run (see +`Structured diagnostics`_); ``--list-functions`` and archive replay +(``--obligation-in``), which prints a line per module, have none. - ``--quiet`` prints only what needs attention: failures, unresolved results, errors, warnings, bounded results, and interrupted functions, then the @@ -695,9 +697,12 @@ Backends * - ``--proof-cache-max-entries=N`` - Bound the number of proof-cache records (default 100000; ``0`` disables the entry limit). Requires ``--proof-cache``. - * - ``--diagnostics-format={text,json}`` - - Select Clang-style text (default) or versioned JSON Lines for verification - results. JSON records use schema ``cppverify.diagnostic/1``. + * - ``--diagnostics-format={text,json,sarif,github}`` + - Select Clang-style text (default); JSON Lines of + ``cppverify.diagnostic/2`` records ending with a + ``cppverify.summary/1`` record; one SARIF 2.1.0 log at the end of the + run; or the text with a GitHub workflow annotation for each error and + warning (see `Structured diagnostics`_). * - ``--lower-only`` - Run Clang conversion, backend-specific preparation, passivization, canonical Obligation IR construction, spec-axiom encoding, and selected @@ -876,19 +881,81 @@ The check that a function's contract is defined (see :doc:`functions-loops`) is reported only when it fails, as ``contract of f``, with the definedness kinds above; JSON records give ``f`` as the function. -JSON records also carry each failing check's source-anchored ID, such as -``function-identity::overflow@line:column#2``, as ``obligation.id``, and its -kind as ``obligation.kind``. The local suffix only disambiguates checks of one -kind at the same anchor, so inserting or reordering an unrelated check does -not renumber later IDs unless its source anchor moves. Records include -inclusive source ranges, and each counterexample value has its source name, -its internal SSA name (``ssa_name``), and its exact sort, such as ``bool``, -``i32``, ``u32``, ``math-i32``, ``pointer``, and ``heap``. Z3 model completion -is disabled: undetermined values print as ```` and become JSON -``null``. Signed and unsigned bit-vectors are decoded to source-level decimal -values. A record's ``message`` is the text of its error line; the values and -the path are in ``model`` and ``trace``. Before 0.2 the message also held the -check's ID and every value with its SSA name and sort. +JSON Lines +~~~~~~~~~~ + +``--diagnostics-format=json`` prints one ``cppverify.diagnostic/2`` record +per result, and the run ends with one ``cppverify.summary/1`` record, the +counts of the text summary by name (``verified``, ``failed``, +``unresolved`` with its ``reasons``, ``bounded_safe``, ``trusted``, +``lowered``, ``exported``, ``interrupted``). No record holds a time, so a +run's records are the same at any ``--jobs``; ``--time-report`` adds +``cppverify.time/1`` records. A record has: + +- ``status`` (``verified``, ``failed``, ``unresolved``, ``warning``, + ``frontend``, ...), ``severity`` (``error``, ``warning``, ``note``), and + ``message``, the text of its line; for a failure, ``reason``; +- ``function``, and ``function_source``, the function's name where it is + declared; +- ``source``, what the result is about: for a failure the expression its + check checks. A source is ``file``, ``line``, ``column``, ``end_line``, + ``end_column``: from its first character to the column after its last, as + SARIF and editors count, on presumed (``#line``) lines; +- for a failure, ``obligation`` with the check's ``id`` and ``kind``; + ``counterexample``, the values as the note prints them; ``model``, every + value with its source name, its internal SSA name (``ssa_name``), its sort + (``bool``, ``i32``, ``u32``, ``math-i32``, ``pointer``, ``heap``, ...), and + ``"on_path": false`` for a version of a branch the path does not take; and + ``trace``, each step with its ``kind``, its ``text`` as the note prints it, + and ``active``; +- ``notes``, ``backend``, ``bound``, ``trusts``, ``vacuous``, ``partial``, + ``instantiated_at``, and the other qualifiers of the text. + +The check's ID is source-anchored, such as +``function-identity::overflow@line:column#2``: the line and column of its +caret. The local suffix only disambiguates checks of one kind at the same +anchor, so inserting or reordering an unrelated check does not renumber later +IDs unless its source anchor moves. Z3 model completion is disabled: +undetermined values print as ```` and become JSON ``null``. Signed +and unsigned bit-vectors are decoded to source-level decimal values. + +The compiler's own diagnostics are records of status ``frontend``: a parse +error, a warning with its ``option`` (``-Wparentheses``), each with the notes +that follow it as ``related``, a message and a source each. They come before +the verifier's records of their file. Only an error in ``cpp-verify``'s own +options, which stops the run before it starts, stays text on standard error. + +Before 0.2 the schema was ``cppverify.diagnostic/1``: a record had no +``function_source``, and none for a verified function at all; a source +started at the check's caret and ended at the first column of its last token; +the message held the check's ID and every value with its SSA name and sort; +compiler errors were text; and no record ended the run. + +SARIF +~~~~~ + +``--diagnostics-format=sarif`` prints one SARIF 2.1.0 log when the run ends, +made from the same records, for GitHub code scanning and SARIF viewers. Each +record is a result, after Frama-C's mapping of property statuses: a proof +passes (``kind: pass``), a failure fails (``fail``, level ``error``), and a +result no verdict settles stays open (``open``). The result's rule is the +kind of the failing check (``postcondition``, ``overflow``, ...), or +``verified``, ``unresolved``, ``warning``, ``frontend``; its location is the +record's source and its function, its message the text with the +counterexample, and the path a code flow, each step at its line with its +text. The run's properties hold the summary. + +GitHub annotations +~~~~~~~~~~~~~~~~~~ + +``--diagnostics-format=github`` prints the text, and after each error and +warning a workflow command that GitHub Actions turns into an annotation on +the source, its file relative to the working directory (the checkout, in a +workflow). For ``summary.cpp`` above, after the error and its notes: + +.. code-block:: text + + ::error file=summary.cpp,line=14,col=12,endLine=14,endColumn=34,title=cpp-verify%3A postcondition::verification failed: add_two [postcondition] [backend=z3] [reason=counterexample]%0Acounterexample: x = 3, result = 5 Counterexample traces may contain guarded branch, modular-call, loop, heap-write, allocation/provenance, lifetime-end, deletion, and return events. @@ -1039,11 +1106,10 @@ paths through a call. Unreachable code itself is not flagged: a defensive good reason, and every claim the function makes is still checked on the paths that remain. -``--diagnostics-format=json`` covers verification-result diagnostics. -Command-line validation and frontend parse errors may still use text. Combining -JSON diagnostics with IR dumps intentionally creates a mixed stream. Malformed -byte sequences in source or archive display text are rendered with the Unicode -replacement character, so every emitted JSON record remains valid UTF-8. +Combining JSON or SARIF with IR dumps intentionally creates a mixed stream. +Malformed byte sequences in source or archive display text are rendered with +the Unicode replacement character, so every emitted JSON record remains valid +UTF-8. Portable obligation archives ---------------------------- @@ -1100,7 +1166,7 @@ module is ``BoundedSafe`` when every goal but some unwinding goal certifies (:doc:`../book/part-ii/ch17-backends-modular-calls`). ``--lean-fallback`` applies to source verification only. -``--obligation-out`` writes ``cppverify.obligation/4`` records only after exact +``--obligation-out`` writes ``cppverify.obligation/5`` records only after exact serialize/deserialize/validate/reserialize checks. Stable wire tags make the format independent of C++ enum ordinals. The reader rejects malformed magic, unsupported versions, truncation, invalid tags, inconsistent feature @@ -1110,9 +1176,12 @@ termination measures, read like its definition, and, with source metadata, where each assumption of a goal comes from, which names a hypothesis of a readable Lean goal; schema v4, with source metadata, where each variable version of a counterexample is defined, so a replayed counterexample lists the -values its path takes. Records of schemas v3 and v2, and of schema v1, which -name only assertions, postconditions, and unwinding checks, are still read; a -counterexample replayed from one before v4 lists the values of every version. +values its path takes; schema v5 where each source range begins, its end +being the column after its last character. Records of schemas v4 to v2, and +of schema v1, which name only assertions, postconditions, and unwinding +checks, are still read; a counterexample replayed from one before v4 lists +the values of every version, and a range from one before v5 begins at its +anchor and ends at the first column of its last token. Records cap integer widths at 4096 bits, expression depth at 4096, and collections plus expression nodes/edges at 100,000 per record. It also rejects embedded NULs, non-canonical numerals, inactive payload fields, ill-scoped From 1b60e49febee0d5e63f550d9fc1487372523d6d4 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:41 +0530 Subject: [PATCH 192/259] docs: Note JSON v2, SARIF, GitHub annotations, and archive schema v5. --- website/source/release-notes.rst | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/website/source/release-notes.rst b/website/source/release-notes.rst index 2d43fb50cb..6252856429 100644 --- a/website/source/release-notes.rst +++ b/website/source/release-notes.rst @@ -483,6 +483,19 @@ are errors at the statement (:doc:`language/functions-loops`). Running cpp-verify ~~~~~~~~~~~~~~~~~~ +**Results as records, SARIF, and annotations.** JSON records had no source +for a verified function, a failure's range began at its caret and ended at +the first column of its last token, compiler errors stayed text, and nothing +ended the run; there was no SARIF. JSON records are now +``cppverify.diagnostic/2``: every one names its function and where it is +declared, a failure spans its whole expression to the column after its last +character and gives its counterexample and path as the text prints them, the +compiler's own errors and warnings are records with their notes, and a +``cppverify.summary/1`` record ends the run. ``--diagnostics-format=sarif`` +writes one SARIF 2.1.0 log for code scanning, each failure with its path as +a code flow, and ``--diagnostics-format=github`` annotates errors and +warnings in a GitHub workflow (:doc:`language/tooling`). + **Failures read like compiler errors.** A failure was one line that named its obligation by an internal identity and listed every SSA version of every variable with its type (``verification failed: abs @@ -503,8 +516,7 @@ diagnostic of its own instead of printing the verifier's text and then one a warning belongs to ``-Wcppverify`` (so ``-Wno-cppverify`` and ``-Werror=cppverify`` work), a proof is a remark shown with ``-Rcppverify``, and ``-fdiagnostics-format=sarif`` carries them all. In JSON Lines a record's -``message`` is the new error text; its other fields are unchanged -(:doc:`language/tooling`). +``message`` is the new error text (:doc:`language/tooling`). **Counterexamples after a loop.** A failure whose counterexample passed through a loop looked like any other, though its state there came from the @@ -781,10 +793,11 @@ refuses a ``lake`` outside elan that reports another Lean Data formats ~~~~~~~~~~~~ -Archives are ``cppverify.obligation/4``, which adds measures, the sources -of assumptions, and where each variable version is defined, and reads ``/3``, -``/2``, and ``/1``; JSON diagnostics stay -``cppverify.diagnostic/1``. A module whose specs' measures apply other specs +Archives are ``cppverify.obligation/5``, which adds measures, the sources +of assumptions, where each variable version is defined, and where each +source range begins, and reads ``/4`` to ``/1``; JSON diagnostics are +``cppverify.diagnostic/2``, ending with a ``cppverify.summary/1`` record, and +``--diagnostics-format=sarif`` writes SARIF 2.1.0. A module whose specs' measures apply other specs keeps them, so its module hash changes; per-obligation hashes, and the proof cache keyed by them, do not. JSON records may carry the status ``proved-obligations`` (archive replay) and the reason ``interrupted`` From d166f2e3094a3c984464f13557bc2da5a4bc531b Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:41 +0530 Subject: [PATCH 193/259] docs: Count SARIF and GitHub annotations among the shipped diagnostics. --- website/source/language/limitations.rst | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/website/source/language/limitations.rst b/website/source/language/limitations.rst index 4ee58a1948..df909a5e9e 100644 --- a/website/source/language/limitations.rst +++ b/website/source/language/limitations.rst @@ -700,7 +700,8 @@ Diagnostics and developer tooling Diagnostics name each obligation they report by a stable source-anchored ID and range, show counterexamples with source variable names and a trace of branches, calls, loops, heap writes, and lifetimes, and are also emitted as -JSON Lines (``--diagnostics-format=json``). ``--profile-quantifiers`` reports +JSON Lines (``--diagnostics-format=json``), SARIF (``sarif``), and GitHub +annotations (``github``). ``--profile-quantifiers`` reports quantifier instantiations, ``--solver-rlimit`` sets reproducible solver budgets, and clangd, built with the tool, provides editor integration. Production readiness still needs: @@ -768,8 +769,8 @@ P4 — libraries and application ecosystem ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Add verified/conformance-tested standard-library models, mathematical views, -build-system integration, SARIF diagnostics, and stable multi-file incremental -verification. clangd support and JSON Lines diagnostics already ship. +build-system integration, and stable multi-file incremental verification. +clangd support, JSON Lines and SARIF diagnostics already ship. P5 — advanced systems C++ ~~~~~~~~~~~~~~~~~~~~~~~~~ From f87ba7ef2471f02495c5f156b9d7c9b92ff79de0 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:42 +0530 Subject: [PATCH 194/259] docs: Name the JSON, SARIF, and GitHub formats in chapter 15. --- website/source/book/part-ii/ch15-toolchain-and-flags.rst | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/website/source/book/part-ii/ch15-toolchain-and-flags.rst b/website/source/book/part-ii/ch15-toolchain-and-flags.rst index 377199a3ff..9215d0ff70 100644 --- a/website/source/book/part-ii/ch15-toolchain-and-flags.rst +++ b/website/source/book/part-ii/ch15-toolchain-and-flags.rst @@ -99,7 +99,10 @@ Other flags - ``cpp-verify --proof-cache=DIR`` — keep proofs of single obligations between runs (``--proof-cache-max-mb``, ``--proof-cache-max-entries`` bound it) - ``cpp-verify --diagnostics-format=json`` — emit versioned - ``cppverify.diagnostic/1`` JSON Lines for verification results + ``cppverify.diagnostic/2`` JSON Lines for results and compiler diagnostics, + ending with a summary record; ``sarif`` prints one SARIF 2.1.0 log, and + ``github`` the text with a GitHub Actions annotation for each error and + warning - ``cpp-verify --lean-out=FILE`` — write a standalone Lean scratch-pad (``--backend=lean``, which it selects) - ``cpp-verify --lean-project=DIR`` — generate a preserved, pinned Lean project From 46944727e7bb3ccdb932d879ec07200083912e80 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:42 +0530 Subject: [PATCH 195/259] docs: Describe JSON v2 records and CI output in chapter 16. --- .../part-ii/ch16-when-verification-fails.rst | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/website/source/book/part-ii/ch16-when-verification-fails.rst b/website/source/book/part-ii/ch16-when-verification-fails.rst index 67c0d310f3..f3a3fa33d4 100644 --- a/website/source/book/part-ii/ch16-when-verification-fails.rst +++ b/website/source/book/part-ii/ch16-when-verification-fails.rst @@ -26,14 +26,22 @@ For editor, CI, and agent integration, run: cpp-verify --diagnostics-format=json file.cpp -Each verification result is one ``cppverify.diagnostic/1`` JSON object with a -stable reason code, backend and optional BMC bound, inclusive source range, -obligation ID/kind, typed model values, and trace. An unknown model value is -JSON ``null``. An undetermined path guard is ``"active": null`` rather than an -arbitrary branch choice. Command-line and frontend parse errors may still be -text, and IR dumps intentionally make the stream mixed. Malformed display bytes -are replaced with the Unicode replacement character, so JSON output remains -valid UTF-8. +Each verification result is one ``cppverify.diagnostic/2`` JSON object with a +stable reason code, backend and optional BMC bound, the function and where it +is declared, the source range of the failing expression (to the column after +its last character), obligation ID/kind, typed model values, the +counterexample and each step of the path as the text prints them, and the +trace. An unknown model value is JSON ``null``. An undetermined path guard is +``"active": null`` rather than an arbitrary branch choice. The compiler's own +errors and warnings are records too, and a summary record ends the run. IR +dumps intentionally make the stream mixed. Malformed display bytes are +replaced with the Unicode replacement character, so JSON output remains valid +UTF-8. + +In a GitHub workflow, ``--diagnostics-format=sarif`` writes a SARIF log that +``github/codeql-action/upload-sarif`` turns into code-scanning alerts, each +failure with its path, and ``--diagnostics-format=github`` annotates the +failing lines of a pull request directly (see :doc:`../../language/tooling`). A counterexample after a loop is only as real as the loop's invariants. At the loop, the verifier knows what the invariants say and nothing else, so a From a9de50def5aa31e242c62eded2500aa14e18e626 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:42 +0530 Subject: [PATCH 196/259] docs: Name archive schema v5 in chapter 17. --- website/source/book/part-ii/ch17-backends-modular-calls.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/source/book/part-ii/ch17-backends-modular-calls.rst b/website/source/book/part-ii/ch17-backends-modular-calls.rst index b546a9d096..1bec4593f1 100644 --- a/website/source/book/part-ii/ch17-backends-modular-calls.rst +++ b/website/source/book/part-ii/ch17-backends-modular-calls.rst @@ -1028,7 +1028,7 @@ The canonical backend boundary can be persisted and replayed: cpp-verify --obligation-in=goals.cpv --backend=lean --lean-out=goals.lean cpp-verify --obligation-in=goals.cpv --lean-project=proof --lean-certify -Each ``cppverify.obligation/4`` record uses stable wire tags, defensive bounds, +Each ``cppverify.obligation/5`` record uses stable wire tags, defensive bounds, portable source points, and path-independent SHA-256 semantic hashes. Replay revalidates every sort, expression, logical declaration, call signature, feature declaration, and identity before backend dispatch. Multiple records may From 6fa7efdb78bf15981a085acfa185ca9c9c2d7d77 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:43 +0530 Subject: [PATCH 197/259] test: Expect cppverify.diagnostic/2 records in located_errors.cpp. --- clang/test/Verify/located_errors.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/located_errors.cpp b/clang/test/Verify/located_errors.cpp index afc9b9cdb6..eac6da6a68 100644 --- a/clang/test/Verify/located_errors.cpp +++ b/clang/test/Verify/located_errors.cpp @@ -16,7 +16,7 @@ int pick(int x) // CHECK: {{.*}}located_errors.cpp:[[@LINE-2]]:14: error: pick: throw is unsupported: exceptions are not modeled // CHECK-NEXT: {{^ +}}[[@LINE-3]] | if (x < 0) throw x; return 0; // CHECK-NEXT: {{^ +}}| ^~~~~~~ -// JSON: {"function":"pick","message":"pick: throw is unsupported: exceptions are not modeled","reason":"construct.unsupported","schema":"cppverify.diagnostic/1","severity":"error","source":{"column":14,"end_column":20,"end_line":[[#@LINE-5]],"file":"{{.*}}located_errors.cpp","line":[[#@LINE-5]]},"status":"unresolved"} +// JSON: {"function":"pick","function_source":{"column":5,"end_column":9,"end_line":[[#@LINE-8]],"file":"{{.*}}located_errors.cpp","line":[[#@LINE-8]]},"message":"pick: throw is unsupported: exceptions are not modeled","reason":"construct.unsupported","schema":"cppverify.diagnostic/2","severity":"error","source":{"column":14,"end_column":21,"end_line":[[#@LINE-5]],"file":"{{.*}}located_errors.cpp","line":[[#@LINE-5]]},"status":"unresolved"} struct Shape { virtual int get(int x) { cv::check(x >= 0 || x < 0); return x; } @@ -50,4 +50,4 @@ int down(int n) // CHECK: {{.*}}located_errors.cpp:[[@LINE-8]]:5: error: down: recursive executable functions require decreases, or cppverify::decreases(*) to allow divergence // CHECK-NEXT: {{^ +}}[[@LINE-9]] | int down(int n) // CHECK-NEXT: {{^ +}}| ^~~~ -// JSON: {"function":"down","message":"down: recursive executable functions require decreases, or cppverify::decreases(*) to allow divergence","reason":"construct.unsupported",{{.*}}"status":"unresolved"} +// JSON: {"function":"down",{{.*}}"message":"down: recursive executable functions require decreases, or cppverify::decreases(*) to allow divergence","reason":"construct.unsupported",{{.*}}"status":"unresolved"} From 13babaa1454c79bfe0a23ac3775ab2f0b5b453b2 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:43 +0530 Subject: [PATCH 198/259] test: Expect cppverify.diagnostic/2 records in backend_model_names.cpp. --- clang/test/Verify/suite/backend_model_names.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/backend_model_names.cpp b/clang/test/Verify/suite/backend_model_names.cpp index a0bc20de6d..4481c1cce5 100644 --- a/clang/test/Verify/suite/backend_model_names.cpp +++ b/clang/test/Verify/suite/backend_model_names.cpp @@ -15,4 +15,4 @@ unsigned renamed_parameter(unsigned implementation_name) { // JSON: "name":"implementation_name" // JSON-SAME: "sort":"u32" // JSON-SAME: "ssa_name":"interface_name_0" -// JSON-SAME: "schema":"cppverify.diagnostic/1" +// JSON-SAME: "schema":"cppverify.diagnostic/2" From 8e92435e37ec9c85717bc5a148871758ad717294 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:44 +0530 Subject: [PATCH 199/259] test: Expect cppverify.diagnostic/2 records in backend_model_truth.cpp. --- clang/test/Verify/suite/backend_model_truth.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/test/Verify/suite/backend_model_truth.cpp b/clang/test/Verify/suite/backend_model_truth.cpp index b087633dae..a4a6480704 100644 --- a/clang/test/Verify/suite/backend_model_truth.cpp +++ b/clang/test/Verify/suite/backend_model_truth.cpp @@ -18,14 +18,14 @@ int underdetermined_model(int value, bool take_value) // JSON-SAME: {"name":"value","sort":"i32" // JSON-SAME: "ssa_name":"value_0","value":null} // JSON-SAME: "obligation":{"id":"{{.*}}::postcondition@{{[0-9]+}}:{{[0-9]+}}","kind":"postcondition" -// JSON-SAME: "source":{"column":19,"end_column":61,"end_line":8 +// JSON-SAME: "source":{"column":19,"end_column":66,"end_line":8 // JSON-SAME: "reason":"counterexample" -// JSON-SAME: "schema":"cppverify.diagnostic/1" +// JSON-SAME: "schema":"cppverify.diagnostic/2" // JSON-SAME: "status":"failed" // ARCHIVE: "model":[ // ARCHIVE-SAME: {"name":"value","sort":"i32" // ARCHIVE-SAME: "ssa_name":"value_0","value":null} // ARCHIVE-SAME: "semantic_hash":"sha256:{{[0-9a-f]+}}" -// ARCHIVE-SAME: "source":{"column":19,"end_column":61,"end_line":8 +// ARCHIVE-SAME: "source":{"column":19,"end_column":66,"end_line":8 // ARCHIVE-SAME: "status":"failed" From a5361c8c4c892148715cf9811f4ed9a653fafa53 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:44 +0530 Subject: [PATCH 200/259] test: Expect cppverify.diagnostic/2 records in backend_stable_id.test. --- clang/test/Verify/suite/backend_stable_id.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/backend_stable_id.test b/clang/test/Verify/suite/backend_stable_id.test index 5a20da88ad..b592ee3a1e 100644 --- a/clang/test/Verify/suite/backend_stable_id.test +++ b/clang/test/Verify/suite/backend_stable_id.test @@ -9,7 +9,7 @@ # CHECK: verification failed: stable_identity [postcondition] # INLINED: "function":"inlined_source" # INLINED-SAME: "id":"{{.*}}::postcondition@4:19" -# INLINED-SAME: "end_column":37 +# INLINED-SAME: "end_column":38 # INLINED-SAME: "line":4 # The suffix separates obligations of one kind at one anchor: here both From 26f9faf412ad6d6d401e4332ff3b1126a139e77d Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:45 +0530 Subject: [PATCH 201/259] test: Expect cppverify.diagnostic/2 records in bmc_incremental.cpp. --- clang/test/Verify/suite/bmc_incremental.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/bmc_incremental.cpp b/clang/test/Verify/suite/bmc_incremental.cpp index b023b37a56..d1c68b5026 100644 --- a/clang/test/Verify/suite/bmc_incremental.cpp +++ b/clang/test/Verify/suite/bmc_incremental.cpp @@ -69,7 +69,7 @@ int open_frontier(int limit) // JSON: "bound":0,"explored_bounds":[0],"function":"loop_free" // JSON: "bound":2,"explored_bounds":[0,1,2],"function":"completes_at_two" // JSON-SAME: "reused_queries":{{[1-9][0-9]*}} -// JSON: "bound":2,"explored_bounds":[0,1,2],"function":"bug_on_second_iteration" +// JSON: "bound":2,{{.*}}"explored_bounds":[0,1,2],"function":"bug_on_second_iteration" // JSON-SAME: "message":"iteration 1" // JSON-SAME: "message":"iteration 2" // JSON: "bound":4,"explored_bounds":[0,1,2,3,4],"function":"open_frontier" From 76c14663cb871dabfcbd05a93af668b8bfc40de5 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:45 +0530 Subject: [PATCH 202/259] test: Expect cppverify.diagnostic/2 records in contracts_across_files.test. --- clang/test/Verify/suite/contracts_across_files.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/contracts_across_files.test b/clang/test/Verify/suite/contracts_across_files.test index 13ea35a459..5951869829 100644 --- a/clang/test/Verify/suite/contracts_across_files.test +++ b/clang/test/Verify/suite/contracts_across_files.test @@ -39,8 +39,8 @@ ORDER: mathx.h:2:42: error: verification failed: clamp100 ORDER: Unresolved: scaled [backend=z3] [reason=callee.contract] (relies on the contract of clamp100, which its verification in {{.*}}mathx.cpp does not establish) ORDER: Summary: 1 failed, 2 unresolved (callee.contract 2) -JSON: {"backend":"z3","function":"scaled","message":"scaled [backend=z3] [reason=callee.contract] (relies on the contract of clamp100, which its verification in {{.*}}mathx.cpp does not establish)","reason":"callee.contract",{{.*}}"status":"unresolved"} -JSON: "function":"clamp100","message":"verification failed: clamp100 +JSON: {"backend":"z3","function":"scaled",{{.*}}"message":"scaled [backend=z3] [reason=callee.contract] (relies on the contract of clamp100, which its verification in {{.*}}mathx.cpp does not establish)","reason":"callee.contract",{{.*}}"status":"unresolved"} +JSON: "function":"clamp100",{{.*}}"message":"verification failed: clamp100 A file alone is as before: the contract has no definition. ALONE: mathx.h:1:5: warning: clamp100 has a contract but no definition, so its callers are not verified; mark the declaration {{\[\[cppverify::trusted\]\]}} to assume the contract From e93f084c054a2091cbb472a96be457ccdd738a65 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:45 +0530 Subject: [PATCH 203/259] test: Expect cppverify.diagnostic/2 records in counterexample_confirmation.cpp. --- clang/test/Verify/suite/counterexample_confirmation.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/counterexample_confirmation.cpp b/clang/test/Verify/suite/counterexample_confirmation.cpp index adc5c930f3..5650f198cd 100644 --- a/clang/test/Verify/suite/counterexample_confirmation.cpp +++ b/clang/test/Verify/suite/counterexample_confirmation.cpp @@ -190,7 +190,7 @@ cppverify::proof void fib5_small(int n) { } // CHECK-DAG: error: verification failed: fib5_small {{.*}}confirmed by a proof at this input that uses the contract of fib5_at_least_5 -// JSON-DAG: "confirmed_with":["fib5_at_least_5"],"function":"fib5_small" +// JSON-DAG: "confirmed_with":["fib5_at_least_5"],{{.*}}"function":"fib5_small" struct Positive { int x; From 9f604444f7d030070b96de1f0908383b88dbad6f Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:46 +0530 Subject: [PATCH 204/259] test: Expect cppverify.diagnostic/2 records in function_templates.cpp. --- clang/test/Verify/suite/function_templates.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/function_templates.cpp b/clang/test/Verify/suite/function_templates.cpp index 018a905116..bea52d9834 100644 --- a/clang/test/Verify/suite/function_templates.cpp +++ b/clang/test/Verify/suite/function_templates.cpp @@ -65,7 +65,7 @@ signed char twice_char(signed char x) // CHECK-DAG: Unresolved: twice_char [backend=z3] [reason=callee.contract] (relies on the contract of twice, which is not established) // NOTE: error: verification failed: twice // NOTE: function_templates.cpp:[[@LINE-9]]:19: note: in instantiation of function template specialization 'twice' requested here -// JSON: "function":"twice","instantiated_at":{"column":19,"end_column":19,"end_line":[[@LINE-10]],"file":"{{.*}}function_templates.cpp","line":[[@LINE-10]]} +// JSON: "function":"twice",{{.*}}"instantiated_at":{"column":19,"end_column":24,"end_line":[[@LINE-10]],"file":"{{.*}}function_templates.cpp","line":[[@LINE-10]]} // A recursive template calls its own specialization. template From dfa1e23c8854cd71f2179446c7e5f87b64d9f5cd Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:46 +0530 Subject: [PATCH 205/259] test: Expect cppverify.diagnostic/2 records in inductive_rules.cpp. --- clang/test/Verify/suite/inductive_rules.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/inductive_rules.cpp b/clang/test/Verify/suite/inductive_rules.cpp index d70a2edff8..f2cb60fabd 100644 --- a/clang/test/Verify/suite/inductive_rules.cpp +++ b/clang/test/Verify/suite/inductive_rules.cpp @@ -122,4 +122,4 @@ void not_empty(node *a) // UNPROVED: Summary: 5 unresolved ({{.*}}spec.inductive 1) // RUN: not %cpp-verify --solver-rlimit=1 --diagnostics-format=json %S/Inputs/inductive_unproved.cpp -- 2>/dev/null \ // RUN: | FileCheck %s --check-prefix=UNPROVED-JSON -// UNPROVED-JSON: {"message":"inductive predicate: reach [reason=spec.inductive] {{.*}}","reason":"spec.inductive","schema":"cppverify.diagnostic/1","severity":"error","status":"unresolved"} +// UNPROVED-JSON: {"function_source":{{.*}},"message":"inductive predicate: reach [reason=spec.inductive] {{.*}}","reason":"spec.inductive","schema":"cppverify.diagnostic/2","severity":"error","status":"unresolved"} From 4d3c787a84619037252fc53618efd208cee567b1 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:47 +0530 Subject: [PATCH 206/259] test: Expect cppverify.diagnostic/2 records in interrupt.cpp. --- clang/test/Verify/suite/interrupt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/interrupt.cpp b/clang/test/Verify/suite/interrupt.cpp index 714a333f05..b7ebc8da63 100644 --- a/clang/test/Verify/suite/interrupt.cpp +++ b/clang/test/Verify/suite/interrupt.cpp @@ -66,7 +66,7 @@ cppverify::spec int cube(int x) { return x * x * x; } // CHECK-NEXT: Summary: {{.*}} // CHECK-NEXT: exit: 130 -// JSON: "function":"cubes","message":"cubes","reason":"interrupted","schema":"cppverify.diagnostic/1","severity":"error","source":{{.*}}"status":"unresolved" +// JSON: "function":"cubes",{{.*}}"message":"cubes","reason":"interrupted","schema":"cppverify.diagnostic/2","severity":"error","source":{{.*}}"status":"unresolved" // JSON: exit: 130 // Replay stops the same way. From 778881df00097c09dc28c636e5562e2a954c4670 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:47 +0530 Subject: [PATCH 207/259] test: Expect cppverify.diagnostic/2 records in lean_automation.test. --- clang/test/Verify/suite/lean_automation.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/lean_automation.test b/clang/test/Verify/suite/lean_automation.test index cb906ffbd1..1ae7aeb4ef 100644 --- a/clang/test/Verify/suite/lean_automation.test +++ b/clang/test/Verify/suite/lean_automation.test @@ -74,7 +74,7 @@ # SLOW: automation: cppverify_auto 3 did not prove it within 3 s # SLOW: {{^}} sorry{{$}} -# JSON: "function":"next","lean_automatic":3,{{.*}}"status":"exported" +# JSON: "function":"next",{{.*}}"lean_automatic":3,{{.*}}"status":"exported" # CERTIFY: Unresolved: lean obligation: a_slow (Lean certification failed: the proof of {{.*}}::postcondition@2:37: {{.*}}declaration uses `sorry` # CERTIFY-NEXT: Certified: next [backend=Lean] From a95c5eed6a3a10b6644e9316ae742085a2c0175a Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:48 +0530 Subject: [PATCH 208/259] test: Expect cppverify.diagnostic/2 records in lean_refutation.test. --- clang/test/Verify/suite/lean_refutation.test | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/lean_refutation.test b/clang/test/Verify/suite/lean_refutation.test index d0b0fc82ef..d668d941d4 100644 --- a/clang/test/Verify/suite/lean_refutation.test +++ b/clang/test/Verify/suite/lean_refutation.test @@ -72,8 +72,8 @@ # CERTIFY: error: verification failed: pick_one {{.*}}[reason=counterexample]{{$}} # CERTIFY: warning: the counterexample of pick_one is not confirmed in Lean: Lean cannot decide the goal at the counterexample -# JSON: {"backend":"z3","function":"add_one","lean_refuted":true, -# JSON: {"message":"the counterexample of pick_one is not confirmed in Lean: Lean cannot decide the goal at the counterexample","schema":"cppverify.diagnostic/1","severity":"warning","status":"warning"} +# JSON: {"backend":"z3",{{.*}}"function":"add_one",{{.*}}"lean_refuted":true, +# JSON: {"message":"the counterexample of pick_one is not confirmed in Lean: Lean cannot decide the goal at the counterexample","schema":"cppverify.diagnostic/2","severity":"warning","status":"warning"} # CHECKER: fail cppverify_fake_000000_goal_refuted cppverify_fake_000000_goal_refuted proves True, not Not cppverify_fake_000000_goal From 35258ffcc654a2e72c40b7281ce94144d411d18f Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:48 +0530 Subject: [PATCH 209/259] test: Expect cppverify.diagnostic/2 records in lean_replay.test. --- clang/test/Verify/suite/lean_replay.test | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/lean_replay.test b/clang/test/Verify/suite/lean_replay.test index 6b3b9484c1..fe2c4ba48f 100644 --- a/clang/test/Verify/suite/lean_replay.test +++ b/clang/test/Verify/suite/lean_replay.test @@ -90,7 +90,7 @@ # STALE: warning: the Lean proof CppVerify/Proofs/cppverify_tri_nonneg_42a030/cppverify_tri_nonneg_42a030_postcondition_053b1980.lean is kept in Stale/Proofs/cppverify_tri_nonneg_42a030/cppverify_tri_nonneg_42a030_postcondition_053b1980.lean: its function is gone, and no goal has its statement # STALE-NEXT: Exported: lean obligation: sum_small (cppverify_auto proved 7 of 7 goals) [backend=lean, bound=2] -# BACK: {"message":"the Lean proof of fn_5f5a31307472695f6e6f6e6e656769::postcondition@{{[0-9]+}}:{{[0-9]+}} came back from Stale/Proofs/cppverify_tri_nonneg_42a030/cppverify_tri_nonneg_42a030_postcondition_053b1980.lean to CppVerify/Proofs/cppverify_tri_nonneg_42a030/cppverify_tri_nonneg_42a030_postcondition_053b1980.lean, the file of the goal with its statement","schema":"cppverify.diagnostic/1","severity":"warning","status":"warning"} +# BACK: {"message":"the Lean proof of fn_5f5a31307472695f6e6f6e6e656769::postcondition@{{[0-9]+}}:{{[0-9]+}} came back from Stale/Proofs/cppverify_tri_nonneg_42a030/cppverify_tri_nonneg_42a030_postcondition_053b1980.lean to CppVerify/Proofs/cppverify_tri_nonneg_42a030/cppverify_tri_nonneg_42a030_postcondition_053b1980.lean, the file of the goal with its statement","schema":"cppverify.diagnostic/2","severity":"warning","status":"warning"} # BACK-NEXT: {"backend":"lean","function":"tri.decreases",{{.*}}"status":"exported"} # NO-PROJECT: error: --lean-certify, --lean-prune-stale, and --no-lean-auto require --lean-project From f8fcb154103fe73819704758ce2279d1cd74102b Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:48 +0530 Subject: [PATCH 210/259] test: Expect cppverify.diagnostic/2 records in per_function_errors.test. --- clang/test/Verify/suite/per_function_errors.test | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/test/Verify/suite/per_function_errors.test b/clang/test/Verify/suite/per_function_errors.test index 65e02a63e7..6f42beac5b 100644 --- a/clang/test/Verify/suite/per_function_errors.test +++ b/clang/test/Verify/suite/per_function_errors.test @@ -34,9 +34,9 @@ TEXT-NEXT: Verified: uses_twice [backend=z3] TEXT-NEXT: Summary: {{.*}} TEXT-NOT: {{.}} -JSON: {"function":"pick","message":"pick: throw is unsupported: exceptions are not modeled","reason":"construct.unsupported",{{.*}}"line":11},"status":"unresolved"} -JSON: {"function":"lookup","message":"lookup: the global array 'table' is unsupported","reason":"construct.unsupported",{{.*}}"status":"unresolved"} -JSON-NEXT: {"function":"lookup","message":"lookup: unsupported expression in pre",{{.*}}"status":"error"} +JSON: {"function":"pick",{{.*}}"message":"pick: throw is unsupported: exceptions are not modeled","reason":"construct.unsupported",{{.*}}"line":11},"status":"unresolved"} +JSON: {"function":"lookup",{{.*}}"message":"lookup: the global array 'table' is unsupported","reason":"construct.unsupported",{{.*}}"status":"unresolved"} +JSON-NEXT: {"function":"lookup",{{.*}}"message":"lookup: unsupported expression in pre",{{.*}}"status":"error"} JSON: {"backend":"z3","function":"uses_pick",{{.*}}"reason":"callee.contract",{{.*}}"status":"unresolved"} JSON: {"backend":"z3","function":"inc",{{.*}}"status":"verified"} From 4d09972976700f3b58c2c5070dc38fd0bf2c9726 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:24:49 +0530 Subject: [PATCH 211/259] test: Expect cppverify.diagnostic/2 records in replay_dependencies.cpp. --- clang/test/Verify/suite/replay_dependencies.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/replay_dependencies.cpp b/clang/test/Verify/suite/replay_dependencies.cpp index 040bfb02ad..3f43ee04bd 100644 --- a/clang/test/Verify/suite/replay_dependencies.cpp +++ b/clang/test/Verify/suite/replay_dependencies.cpp @@ -63,4 +63,4 @@ int loop_star(int n) // REPLAY-DAG: Proved obligations: loop_star (dependencies not checked in replay) [backend=z3] // JSON-DAG: "function":"bad_callee"{{.*}}"status":"failed" -// JSON-DAG: "function":"caller","message":"dependencies not checked in replay"{{.*}}"status":"proved-obligations" +// JSON-DAG: "function":"caller",{{.*}}"message":"dependencies not checked in replay"{{.*}}"status":"proved-obligations" From 47fb08a0ef409c70afd39a09875b4daed55ccbb7 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:44:19 +0530 Subject: [PATCH 212/259] verify: Describe a certified counterexample in source terms with its path. --- clang/lib/Verify/Backend/Certify.cpp | 62 ++++++++++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/clang/lib/Verify/Backend/Certify.cpp b/clang/lib/Verify/Backend/Certify.cpp index 280b570e84..5f759cb8cd 100644 --- a/clang/lib/Verify/Backend/Certify.cpp +++ b/clang/lib/Verify/Backend/Certify.cpp @@ -4198,6 +4198,68 @@ verify::candidateValues(const ObligationModule &Module, const LogicExpr &Query, return Values; } +void verify::describeCounterexample(const ObligationModule &Module, + const LogicExpr &Query, + CandidateModel &Model, VerifyResult &Result, + const CertifyLimits &Limits) { + auto evaluated = [&](const LogicExpr *Term) -> std::optional { + if (!Term) + return std::nullopt; + return evaluateTerm(Module, *Term, Model, Limits); + }; + auto truth = [&](const LogicExpr *Term) -> std::optional { + std::optional Value = evaluated(Term); + if (!Value || Value->K != LogicValue::Kind::Bool) + return std::nullopt; + return Value->Truth; + }; + const Obligation *Failing = nullptr; + for (const Obligation &Item : Module.Obligations) + if (Item.CounterexampleQuery.get() == &Query) { + Failing = &Item; + break; + } + if (Failing) + Result.Assignment = counterexampleAssignment(*Failing, Model); + + // In the order Z3's models list them, by internal name. + Result.Model = candidateValues(Module, Query, Model); + llvm::sort(Result.Model, + [](const VerifyModelValue &A, const VerifyModelValue &B) { + return A.InternalName < B.InternalName; + }); + for (VerifyModelValue &Value : Result.Model) + if (auto It = Module.DiagnosticVariables.find(Value.InternalName); + It != Module.DiagnosticVariables.end() && It->second.Guard) + Value.OnPath = truth(It->second.Guard.get()); + + Result.Trace.clear(); + const uint64_t Count = + Failing ? std::min(Failing->TraceEventCount, + Module.TraceEvents.size()) + : 0; + for (uint64_t I = 0; I != Count; ++I) { + const DiagnosticTraceEvent &Event = Module.TraceEvents[I]; + std::optional Active = truth(Event.Guard.get()); + if (Active == false) + continue; + VerifyTraceEvent Step; + Step.Kind = Event.Kind; + Step.Message = Event.Message; + Step.Loc = Event.Loc; + Step.Source = Event.Source; + Step.Active = Active; + for (const DiagnosticTraceValue &Value : Event.Values) { + std::optional Given = evaluated(Value.Value.get()); + Step.Values.push_back( + {Value.Label, Value.Value->Sort, + Given ? std::optional(formatLogicValue(*Given)) + : std::nullopt}); + } + Result.Trace.push_back(std::move(Step)); + } +} + std::string verify::shownApplication(const ObligationModule &Module, const LogicExpr &Application, CandidateModel &Model, From 7a1a1510b5227eb4da91dec5a51456299dda1039 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:44:19 +0530 Subject: [PATCH 213/259] verify: Declare describeCounterexample in Certify.h. --- clang/lib/Verify/Backend/Certify.h | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/clang/lib/Verify/Backend/Certify.h b/clang/lib/Verify/Backend/Certify.h index 807761b552..9b4dafc860 100644 --- a/clang/lib/Verify/Backend/Certify.h +++ b/clang/lib/Verify/Backend/Certify.h @@ -252,6 +252,16 @@ std::vector candidateValues(const ObligationModule &Module, const LogicExpr &Query, CandidateModel &Model); +/// Describes in \p Result the counterexample \p Model gives \p Query, an +/// obligation's counterexample query, as a failure shows it: the source +/// variables' values, each version marked on the path or off it, and the +/// steps of the obligation's path, each with its values. What the model +/// leaves open stays undetermined. +void describeCounterexample(const ObligationModule &Module, + const LogicExpr &Query, CandidateModel &Model, + VerifyResult &Result, + const CertifyLimits &Limits = {}); + /// \p Application with its arguments' values under \p Model, as /// "fibo(1000000000)". std::string shownApplication(const ObligationModule &Module, From 52782fed21b8f61698e79a09ca4b7eb91fb44aa0 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:44:20 +0530 Subject: [PATCH 214/259] verify: Describe each counterexample cvc5 finds as Z3's are. --- clang/lib/Verify/Backend/CVC5Backend.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/clang/lib/Verify/Backend/CVC5Backend.cpp b/clang/lib/Verify/Backend/CVC5Backend.cpp index 9d9a1fa0fc..0d65724266 100644 --- a/clang/lib/Verify/Backend/CVC5Backend.cpp +++ b/clang/lib/Verify/Backend/CVC5Backend.cpp @@ -2750,6 +2750,8 @@ CVC5VerifyBackend::verifyQuery(const ObligationModule &Module, Result.Status = VerifyStatus::Failed; Result.Reason = VerifyReason::Counterexample; Result.CertifiedWith = std::move(Certified.Evidence); + describeCounterexample(Module, *Query, Candidate, Result, + checkLimits()); return Result; } } else { @@ -2817,6 +2819,8 @@ CVC5VerifyBackend::verifyQuery(const ObligationModule &Module, Result.Status = VerifyStatus::Failed; Result.Reason = VerifyReason::Counterexample; Result.CertifiedWith = Certified.Evidence; + describeCounterexample(Module, *Query, Candidate, Result, + checkLimits()); return Result; } if (Decision.Next == RefinementDecision::Action::Stop) { From 147c07565d588ddcb2aae3c6e66de24b423a2402 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:44:20 +0530 Subject: [PATCH 215/259] verify: Place a replayed counterexample note at its check. --- clang/tools/cpp-verify/Main.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/clang/tools/cpp-verify/Main.cpp b/clang/tools/cpp-verify/Main.cpp index adc4f01914..b8a3da5ec7 100644 --- a/clang/tools/cpp-verify/Main.cpp +++ b/clang/tools/cpp-verify/Main.cpp @@ -1248,8 +1248,10 @@ static int replayObligationArchive() { llvm::outs() << " (" << Result.Message << ")"; llvm::outs() << Suffix << "\n"; if (std::string Values = verify::counterexampleText(Result); - !Values.empty()) + !Values.empty()) { + printResultSource(); llvm::outs() << "note: counterexample: " << Values << "\n"; + } for (const verify::VerifyTraceEvent &Event : Result.Trace) { if (Event.Source.isValid()) llvm::outs() << Event.Source.File << ":" << Event.Source.Line << ":" From 29e43c57338acb38b84ebc4cfac53513fe924493 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:44:21 +0530 Subject: [PATCH 216/259] test: Check describeCounterexample in CertifyTest. --- clang/unittests/Verify/CertifyTest.cpp | 88 ++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/clang/unittests/Verify/CertifyTest.cpp b/clang/unittests/Verify/CertifyTest.cpp index 9769016bcf..4a6d325d54 100644 --- a/clang/unittests/Verify/CertifyTest.cpp +++ b/clang/unittests/Verify/CertifyTest.cpp @@ -967,6 +967,94 @@ TEST(CertifyTest, FreeSymbolsComeFromTheModel) { EXPECT_NE(Missing.Detail.find("x"), std::string::npos); } +TEST(CertifyTest, CounterexamplesAreDescribedAlongTheFailingPath) { + // int f(int x, bool c, bool d) { int y = 0; if (c) y = 7; else y = 3; + // if (d) {} return y; } with two obligations, the second failing. + const LogicSort I32 = LogicSort::bitVector(32, true); + ObligationModule Module; + auto declare = [&](llvm::StringRef Name, llvm::StringRef Display, + LogicSort Sort, Expr Guard) { + DiagnosticVariable Variable; + Variable.DisplayName = Display.str(); + Variable.Sort = Sort; + if (Guard) + Variable.Guard = LogicExprRef(std::move(Guard)); + Module.DiagnosticVariables.emplace(Name.str(), std::move(Variable)); + }; + auto c = [] { return variable("c_0", LogicSort::boolSort()); }; + declare("y_2", "y", I32, negation(c())); + declare("x_0", "x", I32, nullptr); + declare("y_1", "y", I32, c()); + declare("c_0", "c", LogicSort::boolSort(), nullptr); + auto event = [&](llvm::StringRef Message, Expr Guard) { + DiagnosticTraceEvent Event; + Event.Message = Message.str(); + Event.Guard = std::move(Guard); + Module.TraceEvents.push_back(std::move(Event)); + }; + event("then", c()); + event("else", negation(c())); + event("then", variable("d_0", LogicSort::boolSort())); + event("return", boolLiteral(true)); + Module.TraceEvents.back().Values.push_back( + {"value", node(LogicExpr::Ite, I32, c(), variable("y_1", I32), + variable("y_2", I32))}); + event("after", boolLiteral(true)); + auto query = [&] { + std::vector Terms; + Terms.push_back( + boolean(LogicExpr::Ne, variable("y_2", I32), literal("0", I32))); + Terms.push_back( + boolean(LogicExpr::Eq, variable("x_0", I32), literal("5", I32))); + Terms.push_back( + boolean(LogicExpr::Ne, variable("y_1", I32), literal("0", I32))); + Terms.push_back(c()); + return node(LogicExpr::And, LogicSort::boolSort(), std::move(Terms)); + }; + for (uint64_t Count : {1, 4}) { + Obligation Item; + Item.TraceEventCount = Count; + Item.Goal = negation(query()); + Item.CounterexampleQuery = query(); + Module.Obligations.push_back(std::move(Item)); + } + TableModel Model; + Model.Constants["x_0"] = integerValue(5); + Model.Constants["y_1"] = integerValue(7); + Model.Constants["y_2"] = integerValue(3); + Model.Constants["c_0"] = LogicValue::boolean(true); + + VerifyResult Result; + describeCounterexample(Module, *Module.Obligations[1].CounterexampleQuery, + Model, Result); + std::vector Names; + for (const VerifyModelValue &Value : Result.Model) + Names.push_back(Value.InternalName + "=" + Value.Value.value_or("?") + + (Value.OnPath ? (*Value.OnPath ? " on" : " off") : "")); + EXPECT_EQ(Names, (std::vector{"c_0=true", "x_0=5", "y_1=7 on", + "y_2=3 off"})); + // The path of the second obligation: its first four events, without the + // branch the model does not take, and one it does not decide marked so. + ASSERT_EQ(Result.Trace.size(), 3u); + EXPECT_EQ(Result.Trace[0].Message, "then"); + EXPECT_EQ(Result.Trace[0].Active, std::optional(true)); + EXPECT_EQ(Result.Trace[1].Message, "then"); + EXPECT_EQ(Result.Trace[1].Active, std::nullopt); + EXPECT_EQ(Result.Trace[2].Message, "return"); + ASSERT_EQ(Result.Trace[2].Values.size(), 1u); + EXPECT_EQ(Result.Trace[2].Values[0].Value, std::optional("7")); + // The goal's variables, as a Lean refutation states them. + ASSERT_TRUE(Result.Assignment); + EXPECT_EQ(Result.Assignment->Values.size(), 4u); + EXPECT_EQ(Result.Assignment->Values.at("y_1").key(), integerValue(7).key()); + + VerifyResult First; + describeCounterexample(Module, *Module.Obligations[0].CounterexampleQuery, + Model, First); + ASSERT_EQ(First.Trace.size(), 1u); + EXPECT_EQ(First.Trace[0].Message, "then"); +} + // --- Logical functions // -------------------------------------------------------- From 804ce4f07460827a31cf67cca155dd173c974efa Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:44:21 +0530 Subject: [PATCH 217/259] test: Check cvc5 failure notes in failure_notes_cvc5.test. --- .../test/Verify/suite/failure_notes_cvc5.test | 65 +++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 clang/test/Verify/suite/failure_notes_cvc5.test diff --git a/clang/test/Verify/suite/failure_notes_cvc5.test b/clang/test/Verify/suite/failure_notes_cvc5.test new file mode 100644 index 0000000000..906ee21334 --- /dev/null +++ b/clang/test/Verify/suite/failure_notes_cvc5.test @@ -0,0 +1,65 @@ +# REQUIRES: cvc5 +# A counterexample found by cvc5 is shown as Z3's is (failure_notes.cpp): in +# source terms, each variable with the values it takes along the path, and +# the steps of the path, in text, JSON, and the replay of an archive. +# +# RUN: not %cpp-verify --jobs=1 --backend=cvc5 %S/failure_notes.cpp -- 2>&1 \ +# RUN: | FileCheck %s +# RUN: not %cpp-verify --jobs=1 --backend=cvc5 --diagnostics-format=json \ +# RUN: %S/failure_notes.cpp -- 2>/dev/null | FileCheck %s --check-prefix=JSON +# RUN: not %cpp-verify --jobs=1 --obligation-out=%t.cpv %S/failure_notes.cpp -- > /dev/null 2>&1 +# RUN: not %cpp-verify --obligation-in=%t.cpv --backend=cvc5 2>&1 \ +# RUN: | FileCheck %s --check-prefix=REPLAY +# RUN: not %cpp-verify --jobs=1 --backend=cvc5 %S/Inputs/failure_notes_quantified.cpp -- 2>&1 \ +# RUN: | FileCheck %s --check-prefix=UNKNOWN + +CHECK: failure_notes.cpp:20:23: error: verification failed: steps [postcondition] [backend=cvc5] [reason=counterexample] +CHECK: failure_notes.cpp:20:23: note: counterexample: x = {{9|10}}, y = 0 -> 1 -> 4, result = 4 +CHECK-NOT: false branch +CHECK: failure_notes.cpp:23:3: note: takes the true branch +CHECK-NOT: false branch +CHECK: failure_notes.cpp:27:3: note: takes the true branch +CHECK-NOT: false branch +CHECK: failure_notes.cpp:29:3: note: returns 4 + +CHECK: failure_notes.cpp:54:23: error: verification failed: calls [postcondition] [backend=cvc5] [reason=counterexample] +CHECK: failure_notes.cpp:54:23: note: counterexample: x = [[X:[0-9]+]], result = {{[0-9]+}} +CHECK: failure_notes.cpp:56:3: note: calls add([[X]]) + +CHECK: failure_notes.cpp:107:23: error: verification failed: local [postcondition] [backend=cvc5] [reason=counterexample] +CHECK: failure_notes.cpp:107:23: note: counterexample: v = {{[0-9]+}}, &r = [[R:[0-9]+]], result = [[V:[0-9]+]] +CHECK: failure_notes.cpp:109:3: note: creates a local object at address [[R]] +CHECK: failure_notes.cpp:111:5: note: stores [[V]] at address [[R]] +CHECK: failure_notes.cpp:112:3: note: returns [[V]] + +CHECK: failure_notes.cpp:159:3: note: enters the loop +CHECK: failure_notes.cpp:159:3: note: leaves the loop + +CHECK: note: (skipping 3 steps of the path; JSON lists every one) + +CHECK: failure_notes.cpp:258:3: note: perhaps takes the true branch (the counterexample does not decide whether this step is taken) + +A check inside a loop fails in an iteration of it: its path ends there. +CHECK: failure_notes.cpp:279:5: error: verification failed: iterate [assertion] [backend=cvc5] [reason=counterexample] +CHECK: failure_notes.cpp:275:3: note: enters the loop +CHECK: failure_notes.cpp:275:3: note: starts an arbitrary iteration of the loop, where its condition is true +CHECK-NOT: failure_notes.cpp:{{.*}}: note: +CHECK: note: the counterexample's state at the loop at 275:3 is any state + +The model lists the variables in the order Z3's does, and marks a version +of a branch the path does not take. +JSON: {"backend":"cvc5","counterexample":"x = {{9|10}}, y = 0 -> 1 -> 4, result = 4","function":"steps" +JSON-SAME: "model":[{"name":"result", +JSON-SAME: {"name":"y","on_path":false,"sort":"i32",{{.*}}"ssa_name":"y_3","value":"0"} +JSON-SAME: "trace":[{"active":true,"kind":"branch","message":"then",{{.*}}"text":"takes the true branch"} + +REPLAY: failure_notes.cpp:20:23: error: verification failed: steps [postcondition] [backend=cvc5] [reason=counterexample] [semantic-hash= +REPLAY-NEXT: failure_notes.cpp:20:23: note: counterexample: x = {{9|10}}, y = 0 -> 1 -> 4, result = 4 +REPLAY-NEXT: failure_notes.cpp:23:3: note: takes the true branch + +cvc5 answers unknown where a quantifier is assumed, and prints a model: once +certified, it is described the same way. +UNKNOWN: failure_notes_quantified.cpp:9:23: error: verification failed: first [postcondition] [backend=cvc5] [reason=counterexample] +UNKNOWN: failure_notes_quantified.cpp:9:23: note: counterexample: a = {{[0-9]+}}, n = {{[0-9]+}}, r = 0, result = 0 +UNKNOWN: failure_notes_quantified.cpp:12:3: note: takes the false branch +UNKNOWN: failure_notes_quantified.cpp:14:3: note: returns 0 From ac030bee1d63100ccf20062e8bd42c7edadb239b Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:44:22 +0530 Subject: [PATCH 218/259] test: Add a failure cvc5 answers unknown for failure_notes_cvc5.test. --- .../suite/Inputs/failure_notes_quantified.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 clang/test/Verify/suite/Inputs/failure_notes_quantified.cpp diff --git a/clang/test/Verify/suite/Inputs/failure_notes_quantified.cpp b/clang/test/Verify/suite/Inputs/failure_notes_quantified.cpp new file mode 100644 index 0000000000..fc9987aaf9 --- /dev/null +++ b/clang/test/Verify/suite/Inputs/failure_notes_quantified.cpp @@ -0,0 +1,15 @@ +// A failure whose query cvc5 answers unknown, with a model the certifier +// checks, for failure_notes_cvc5.test. + +namespace cv = cppverify; + +int first(const int *a, int n) + cv::pre(cv::valid(a, n) && n > 2) + cv::pre(cv::forall(k, 0, n, a[k] >= 0)) + cv::post(cv::result > 0) +{ + int r = a[1]; + if (r > 5) + r = r - 1; + return r; +} From c9daecced768b392cbba4ae54de92af7764479b1 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:44:22 +0530 Subject: [PATCH 219/259] test: Expect the replayed counterexample note at its check in failure_notes.cpp. --- clang/test/Verify/suite/failure_notes.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/Verify/suite/failure_notes.cpp b/clang/test/Verify/suite/failure_notes.cpp index 06ad3a2a0c..a59957df9c 100644 --- a/clang/test/Verify/suite/failure_notes.cpp +++ b/clang/test/Verify/suite/failure_notes.cpp @@ -291,7 +291,7 @@ int iterate(int n) // An archive keeps where each version is defined, so its replay lists the // same values. // REPLAY: error: verification failed: steps [postcondition] -// REPLAY-NEXT: note: counterexample: x = {{9|10}}, y = 0 -> 1 -> 4, result = 4 +// REPLAY-NEXT: {{.*}}failure_notes.cpp:[[@LINE-274]]:23: note: counterexample: x = {{9|10}}, y = 0 -> 1 -> 4, result = 4 // JSON: "function":"steps"{{.*}}{"name":"y","on_path":false,"sort":"i32",{{.*}}"ssa_name":"y_3","value":"0"} From 60262f9c7ed1b96ea58ca9b20bad420c85c6d4ea Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:44:22 +0530 Subject: [PATCH 220/259] test: Expect the counterexample of either solver in solver_race.cpp. --- clang/test/Verify/suite/solver_race.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/test/Verify/suite/solver_race.cpp b/clang/test/Verify/suite/solver_race.cpp index 939ce8ddb1..b7be69b2c9 100644 --- a/clang/test/Verify/suite/solver_race.cpp +++ b/clang/test/Verify/suite/solver_race.cpp @@ -34,6 +34,7 @@ int wrong_bound(int x) return x + 1; } // CHECK-DAG: error: verification failed: wrong_bound {{.*}}[backend={{z3|cvc5}}] [reason=counterexample] +// CHECK-DAG: note: counterexample: x = 9, result = 10 // REPLAY-DAG: wrong_bound {{.*}}[reason=counterexample] cppverify::proof void pushed(seq s, int x) From 86fde3c9f35ec322f1fa30432a2d752be2b13f29 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:44:23 +0530 Subject: [PATCH 221/259] docs: Show a cvc5 failure with its counterexample in chapter 17. --- .../part-ii/ch17-backends-modular-calls.rst | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/website/source/book/part-ii/ch17-backends-modular-calls.rst b/website/source/book/part-ii/ch17-backends-modular-calls.rst index 1bec4593f1..552eb0506f 100644 --- a/website/source/book/part-ii/ch17-backends-modular-calls.rst +++ b/website/source/book/part-ii/ch17-backends-modular-calls.rst @@ -73,6 +73,42 @@ malformed process output, and unsupported encoding are ``Unresolved``. cvc5 is not vendored because it is an optional independent implementation; install it through the platform package manager or select an executable explicitly. +A failure cvc5 finds reads like one Z3 finds. Its model is a counterexample +only once the certifier has checked it against the true definitions, and the +certifier then evaluates, in that model, the values of the source variables +along the path and each step of the path to the failing check: + +.. code-block:: cpp + + namespace cv = cppverify; + + int clamp(int x) + cv::pre(x > -100 && x < 100) + cv::post(cv::result >= 0) + { + if (x < 0) + return x + 1; + return x; + } + +.. code-block:: text + + clamp.cpp:5:23: error: verification failed: clamp [postcondition] [backend=cvc5] [reason=counterexample] + 5 | cv::post(cv::result >= 0) + | ~~~~~~~~~~~^~~~ + clamp.cpp:5:23: note: counterexample: x = -2, result = -1 + clamp.cpp:7:3: note: takes the true branch + 7 | if (x < 0) + | ^ + clamp.cpp:8:5: note: returns -1 + 8 | return x + 1; + | ^ + +The JSON record has the same ``counterexample``, ``model``, and ``trace`` +as Z3's, its variables in the same order, and so do SARIF, GitHub +annotations, and archive replay with ``--backend=cvc5``. The values may +differ from Z3's: each solver picks its own counterexample. + Race mode trusts each solver alone, which is sound: a proof is a proof, and a counterexample is reported only once the certifier has checked it against the true definitions, whichever solver found it. The first decisive answer From bc6cc492f1fe82aff4a942919819182f2a780773 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:44:23 +0530 Subject: [PATCH 222/259] docs: Say any solver's undetermined values stay unknown in chapter 16. --- website/source/book/part-ii/ch16-when-verification-fails.rst | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/website/source/book/part-ii/ch16-when-verification-fails.rst b/website/source/book/part-ii/ch16-when-verification-fails.rst index f3a3fa33d4..234807ebf7 100644 --- a/website/source/book/part-ii/ch16-when-verification-fails.rst +++ b/website/source/book/part-ii/ch16-when-verification-fails.rst @@ -15,8 +15,9 @@ by their source names, each variable with the values it takes along the path analyzer reports a path: the branches it takes, the calls with their arguments, the loops it enters and leaves, the memory it writes, the objects it creates and ends, and the value it returns. Use those values and steps to -see which assumption or branch is wrong. Values that Z3 does not determine -remain ````; CppVerify does not complete the model by inventing them. +see which assumption or branch is wrong. Values that the solver's model does +not determine remain ````; CppVerify does not complete the model by +inventing them. ``clang++ -fverify-contracts`` reports the same errors and notes as its own diagnostics. From 88eebc80c8771cb42b7e24db1c9546f27e833a21 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:44:24 +0530 Subject: [PATCH 223/259] docs: Drop the cvc5 counterexample limitation. --- website/source/language/limitations.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/website/source/language/limitations.rst b/website/source/language/limitations.rst index df909a5e9e..29a5b2b071 100644 --- a/website/source/language/limitations.rst +++ b/website/source/language/limitations.rst @@ -614,8 +614,8 @@ remain future work. **cvc5 and strict portfolio** consume the same canonical obligations as Z3 through an independent SMT-LIB2 emitter. cvc5 is optional and system-installed; -its models are checked against the definitions like Z3's but are not yet shown -as source-level values. Strict portfolio mode requires matching decisive +its models are checked against the definitions like Z3's and shown like Z3's, +in source names with the steps of the failing path. Strict portfolio mode requires matching decisive results and preserves Z3's model only after both solvers produce checked counterexamples. cvc5 may return ``unknown`` on quantified or heap-heavy formulas that Z3 solves; strict mode then remains ``Unresolved``. Recursive From c56b1bcbde9b8f2468d55ac4bb4033e2fff844cc Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:44:24 +0530 Subject: [PATCH 224/259] docs: Say cvc5 models are shown as Z3's in tooling. --- website/source/language/tooling.rst | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/website/source/language/tooling.rst b/website/source/language/tooling.rst index 0ed9338fc6..ef5c47c895 100644 --- a/website/source/language/tooling.rst +++ b/website/source/language/tooling.rst @@ -737,7 +737,9 @@ Backend results are intentionally distinct. Z3 ``unsat`` reports ``Verified``; a ``sat`` model reports a failed source obligation once it is checked against the true definitions (otherwise ``Unresolved`` with a reason); timeout and ``unknown`` report ``Unresolved``. cvc5 follows the same mapping, and its models -are checked the same way. +are checked the same way, then shown the same way: a failure's counterexample +and path, in text and in JSON's ``counterexample``, ``model``, and ``trace``, +come from the checked model. Portfolio mode requires agreement; an agreed ``sat`` result uses Z3's typed model and trace, while disagreement or incomplete secondary evidence is ``Unresolved``. BMC reports ``BoundedSafe: f [backend=bmc, bound=N]`` when only its unwinding From 34bb2c708295e08f7503ed8c4c15a2d65e893b20 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:44:25 +0530 Subject: [PATCH 225/259] docs: Note cvc5 counterexamples in the 0.2.0 release notes. --- website/source/release-notes.rst | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/website/source/release-notes.rst b/website/source/release-notes.rst index 6252856429..58d5b02455 100644 --- a/website/source/release-notes.rst +++ b/website/source/release-notes.rst @@ -518,6 +518,16 @@ a warning belongs to ``-Wcppverify`` (so ``-Wno-cppverify`` and and ``-fdiagnostics-format=sarif`` carries them all. In JSON Lines a record's ``message`` is the new error text (:doc:`language/tooling`). +**cvc5's counterexamples.** A failure cvc5 found (``--backend=cvc5``, or a race +cvc5 won) gave no values and no path: the certifier checked its model and the +verifier then dropped it, so the JSON record had no ``model`` or ``trace``, +and under ``--lean-fallback`` a race cvc5 won wrote no Lean refutation (``the +solver's model gives the goal's variables no values``). It now shows the +counterexample and the steps of its path exactly as a failure Z3 finds does, +in text, JSON, SARIF, GitHub annotations, and archive replay, evaluated by the +certifier in the checked model; the race's refutation states its values +(:doc:`book/part-ii/ch17-backends-modular-calls`). + **Counterexamples after a loop.** A failure whose counterexample passed through a loop looked like any other, though its state there came from the loop's invariants and no execution need reach it: the first loop most users From ddf9a1707971a24e9234c0d8ca183d2d266b97b8 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:44:25 +0530 Subject: [PATCH 226/259] docs: Describe describeCounterexample in ARCHITECTURE. --- docs/ARCHITECTURE.md | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 98ef5abdae..42a0e30c69 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -2397,7 +2397,20 @@ Passivization also records guarded branch, modular-call, loop, heap-write, allocation, lifetime-end, deletion, and return events. Each obligation owns the event prefix that existed when it was emitted. The Z3 model removes events with false guards, retains true events, and marks undetermined guards explicitly -unknown. Addresses, stored values, allocation identities, and return values use +unknown. + +cvc5's models are read by the adapter, not by a solver API, so the certifier +describes them (`describeCounterexample`, `Certify.cpp`) once it has certified +one: in the model it checked, `evaluateTerm` gives each source variable of the +obligation's query (`candidateValues`, listed by internal name, the order of +Z3's models), the guard of each version (`OnPath`), each of the obligation's +trace events up to its `TraceEventCount` (dropped when the guard is false, +marked undetermined when the model does not decide it) and its values, and +the assignment of the goal's variables that a Lean refutation states. The +evaluation is the certifier's own, the semantics the counterexample was +certified in, so a value shown is one the check used; it never completes the +model. cvc5 solves each obligation alone, so the query is always one +obligation's. Addresses, stored values, allocation identities, and return values use the same typed, non-completing evaluation. A complete-query counterexample is attributed to a specific ordered obligation whenever its model evaluates that obligation's counterexample query to true. @@ -2637,7 +2650,7 @@ The driver selects a backend via `VerifyOptions` (`Verifier.h` / `cpp-verify --b | Backend | Implementation | Notes | |---------|----------------|-------| | **Z3** | `Z3VerifyBackend` | Default. Consumes `ObligationModule`; counterexamples come from models. | -| **cvc5** | `CVC5VerifyBackend` + standalone SMT-LIB2 | Encodes the same canonical sorts, C++ truncating math division/remainder, bit-vectors, signed overflow, total heap, bounded and unbounded quantifiers (marked triggers as `:pattern`), heap frames, sequences (`full-saturate-quant` when sequences meet quantifiers), and finite ground spec equations. Sets, multisets, and maps are arrays over all integers, as for Z3 (cvc5's own set theory is finite, which would prove facts false of an infinite set): `(Array Int Bool)`, `(Array Int Int)` with a count of `max(0, cell)` and equality count by count, and `(Array Int cppverify.option)` over a declared `none | some(value)` datatype; union, intersection, and difference are declared functions each defined pointwise by one quantified axiom, exact by array extensionality, and subset is a quantified formula. A model cvc5 prints with `unknown` is certified like one after `sat`. Solver process failures and malformed output are unresolved. | +| **cvc5** | `CVC5VerifyBackend` + standalone SMT-LIB2 | Encodes the same canonical sorts, C++ truncating math division/remainder, bit-vectors, signed overflow, total heap, bounded and unbounded quantifiers (marked triggers as `:pattern`), heap frames, sequences (`full-saturate-quant` when sequences meet quantifiers), and finite ground spec equations. Sets, multisets, and maps are arrays over all integers, as for Z3 (cvc5's own set theory is finite, which would prove facts false of an infinite set): `(Array Int Bool)`, `(Array Int Int)` with a count of `max(0, cell)` and equality count by count, and `(Array Int cppverify.option)` over a declared `none | some(value)` datatype; union, intersection, and difference are declared functions each defined pointwise by one quantified axiom, exact by array extensionality, and subset is a quantified formula. A model cvc5 prints with `unknown` is certified like one after `sat`, and a certified one is described in source terms as Z3's is (`describeCounterexample`). Solver process failures and malformed output are unresolved. | | **Strict portfolio** | `PortfolioVerifyBackend` | Runs ordered Z3 and cvc5 queries. Matching UNSAT proves; matching certified counterexamples fail and retain the Z3 model; disagreement or an unresolved side is unresolved. | | **Race** | `RaceVerifyBackend` | Runs the Z3 and cvc5 backends at once; the first proof or certified counterexample stands and cancels the other (`cancel`/`resume`: a backend-wide `Race` of Z3 encoders, each forwarding an interrupt to the pass it runs, and a flag the cvc5 process loop polls). Otherwise the obligations either proved are joined, `Verified` (`z3+cvc5`) when they cover the module. | | **BMC** | `LoopUnroll` on VCR, then shared obligation/Z3 path | Source verification grows bounds from zero through `--unroll=N`, stopping on a counterexample, complete unwinding, unresolved query, or the maximum frontier. Safety with failed unwinding is `BoundedSafe(N)`; only proved unwinding is `Verified`. A spec's checks have no loops: the driver solves them with a Z3 backend (`SpecBackend`), as on the default path, and keeps the bound on their archived modules for replay. | From 2d740bae858f7e767aeb4d646b7a08dda533f8f0 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 04:44:25 +0530 Subject: [PATCH 227/259] docs: Say cvc5 failures read like Z3 ones in DESIGN. --- docs/DESIGN.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/DESIGN.md b/docs/DESIGN.md index 47acb4d459..43d809e43e 100644 --- a/docs/DESIGN.md +++ b/docs/DESIGN.md @@ -2384,7 +2384,8 @@ the finite ground equations of recursive ones. It runs an installed executable w seed/resource options and bounded output; missing tools, invocation failures, timeouts, `unknown`, extra diagnostics, and malformed tokens are unresolved. The model cvc5 prints after `sat`, and often after `unknown`, is checked by the -same certifier as Z3's, and +same certifier as Z3's, which then evaluates in it the counterexample's +source values and path, so a cvc5 failure reads like a Z3 one, and refinement re-runs cvc5 with definition instances. Once a hidden instance has been given, non-recursive definitions are given whole; recursive ones never are, because cvc5 does not decide queries over them. From 7c3cb1afea89fcc049e7c03ce1000e4e6029e8ac Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 05:23:10 +0530 Subject: [PATCH 228/259] verify: Declare the SMT-LIB query dump in QueryDump.h. --- clang/lib/Verify/Backend/QueryDump.h | 58 ++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) create mode 100644 clang/lib/Verify/Backend/QueryDump.h diff --git a/clang/lib/Verify/Backend/QueryDump.h b/clang/lib/Verify/Backend/QueryDump.h new file mode 100644 index 0000000000..0f9ac38ef6 --- /dev/null +++ b/clang/lib/Verify/Backend/QueryDump.h @@ -0,0 +1,58 @@ +//===--- QueryDump.h - Solver queries as SMT-LIB scripts --------*- C++ -*-===// +#ifndef LLVM_CLANG_VERIFY_BACKEND_QUERYDUMP_H +#define LLVM_CLANG_VERIFY_BACKEND_QUERYDUMP_H + +#include "Obligation.h" +#include "llvm/ADT/StringRef.h" +#include + +namespace clang { +namespace verify { + +/// Writes every query sent to a solver under \p Directory, each as a script +/// the solver replays on its own (--dump-smt2); an empty directory turns it +/// off. \p Tool names the program in each script's header. +void setQueryDumpDirectory(std::string Directory, std::string Tool); + +/// Whether queries are being written. +bool queryDumpEnabled(); + +/// The first error writing a query, empty when there was none. +std::string queryDumpError(); + +/// The file of \p Query of \p Module solved by \p Solver whose script is +/// \p Script, relative to the dump directory: +/// `-
/.-.smt2`. +std::string queryDumpPath(const ObligationModule *Module, + const LogicExpr *Query, llvm::StringRef Solver, + llvm::StringRef Script); + +/// One query's script: written when the dump starts, before the check, so +/// that a check that never returns leaves its query, and finished with the +/// solver's answer. +class QueryDump { +public: + QueryDump() = default; + QueryDump(const QueryDump &) = delete; + QueryDump &operator=(const QueryDump &) = delete; + + /// Writes \p Options, the solver's settings as commands, then \p Script, + /// which ends with its check, after a header that names \p Solver + /// (\p SolverVersion) and what \p Query of \p Module is. Does nothing + /// unless dumping is on. + void start(const ObligationModule *Module, const LogicExpr *Query, + llvm::StringRef Solver, llvm::StringRef SolverVersion, + llvm::StringRef Options, llvm::StringRef Script); + + /// Appends \p Commands, run after the check (such as `(get-model)`), and + /// the answer, `; cpp-verify: sat`. + void finish(llvm::StringRef Answer, llvm::StringRef Commands = ""); + +private: + std::string Path; +}; + +} // namespace verify +} // namespace clang + +#endif From 8cd821225ccd1839a510165163dcb762eaf8f891 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 05:23:10 +0530 Subject: [PATCH 229/259] verify: Write each solver query as a standalone SMT-LIB script. --- clang/lib/Verify/Backend/QueryDump.cpp | 204 +++++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 clang/lib/Verify/Backend/QueryDump.cpp diff --git a/clang/lib/Verify/Backend/QueryDump.cpp b/clang/lib/Verify/Backend/QueryDump.cpp new file mode 100644 index 0000000000..913541cca4 --- /dev/null +++ b/clang/lib/Verify/Backend/QueryDump.cpp @@ -0,0 +1,204 @@ +//===--- QueryDump.cpp - Solver queries as SMT-LIB scripts ----------------===// +#include "QueryDump.h" +#include "llvm/ADT/SmallString.h" +#include "llvm/ADT/StringExtras.h" +#include "llvm/Support/FileSystem.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/SHA256.h" +#include "llvm/Support/raw_ostream.h" +#include + +using namespace clang; +using namespace verify; + +namespace { +struct DumpSettings { + std::mutex Lock; + std::string Directory; + std::string Tool; + std::string Error; +}; + +DumpSettings &settings() { + static DumpSettings Settings; + return Settings; +} + +void recordError(std::string Message) { + DumpSettings &S = settings(); + std::lock_guard Guard(S.Lock); + if (S.Error.empty()) + S.Error = std::move(Message); +} + +std::string digest(llvm::StringRef Text, size_t Digits) { + llvm::SHA256 Hash; + Hash.update(Text); + return llvm::toHex(Hash.final(), /*LowerCase=*/true).substr(0, Digits); +} + +/// \p Name with every character but letters, digits, `_`, and \p Kept +/// replaced by `_`, so that it names a file on every system. +std::string fileName(llvm::StringRef Name, llvm::StringRef Kept = "") { + std::string Out; + for (char C : Name.take_front(64)) + Out += llvm::isAlnum(C) || C == '_' || Kept.contains(C) ? C : '_'; + return Out; +} + +const Obligation *obligationOf(const ObligationModule *Module, + const LogicExpr *Query) { + if (Module && Query) + for (const Obligation &Item : Module->Obligations) + if (Item.CounterexampleQuery.get() == Query) + return &Item; + return nullptr; +} + +bool wholeQuery(const ObligationModule *Module, const LogicExpr *Query) { + return Module && (!Query || Query == Module->CounterexampleQuery.get()); +} + +llvm::StringRef stableId(const Obligation &Item) { + return Item.StableId.empty() ? Item.Id : Item.StableId; +} +} // namespace + +void verify::setQueryDumpDirectory(std::string Directory, std::string Tool) { + DumpSettings &S = settings(); + std::lock_guard Guard(S.Lock); + S.Directory = std::move(Directory); + S.Tool = std::move(Tool); + S.Error.clear(); +} + +bool verify::queryDumpEnabled() { + DumpSettings &S = settings(); + std::lock_guard Guard(S.Lock); + return !S.Directory.empty(); +} + +std::string verify::queryDumpError() { + DumpSettings &S = settings(); + std::lock_guard Guard(S.Lock); + return S.Error; +} + +std::string verify::queryDumpPath(const ObligationModule *Module, + const LogicExpr *Query, + llvm::StringRef Solver, + llvm::StringRef Script) { + std::string Function = "query"; + if (Module) { + Function = fileName(Module->FunctionName); + Function += "-" + digest(Module->FunctionIdentity, 6); + } + // An obligation by its stable id, `postcondition@11:23` as + // `postcondition-11-23`. + std::string Name = "query"; + if (wholeQuery(Module, Query)) { + Name = "whole"; + } else if (const Obligation *Item = obligationOf(Module, Query)) { + llvm::StringRef Id = stableId(*Item); + std::string Local = + Id.contains("::") ? Id.rsplit("::").second.str() : Id.str(); + for (char &C : Local) + if (C == '@' || C == ':' || C == '#') + C = '-'; + Name = fileName(Local, "-"); + } + llvm::SmallString<128> Path(Function); + llvm::sys::path::append(Path, Name + "." + Solver.str() + "-" + + digest(Script, 8) + ".smt2"); + return std::string(Path); +} + +void QueryDump::start(const ObligationModule *Module, const LogicExpr *Query, + llvm::StringRef Solver, llvm::StringRef SolverVersion, + llvm::StringRef Options, llvm::StringRef Script) { + std::string Directory, Tool; + { + DumpSettings &S = settings(); + std::lock_guard Guard(S.Lock); + Directory = S.Directory; + Tool = S.Tool; + } + if (Directory.empty()) + return; + const std::string Relative = queryDumpPath(Module, Query, Solver, Script); + llvm::SmallString<256> Full(Directory); + llvm::sys::path::append(Full, Relative); + if (std::error_code EC = llvm::sys::fs::create_directories( + llvm::sys::path::parent_path(Full))) { + recordError("cannot create " + llvm::sys::path::parent_path(Full).str() + + ": " + EC.message()); + return; + } + + std::string Text; + llvm::raw_string_ostream OS(Text); + OS << "; " << Tool << ", " << Solver << ' ' << SolverVersion << "\n"; + if (Module) { + OS << "; " << Module->FunctionName << ": "; + if (wholeQuery(Module, Query)) { + OS << "every obligation at once"; + } else if (const Obligation *Item = obligationOf(Module, Query)) { + OS << "the " << obligationKindName(Item->Kind) << " check"; + if (Item->Source.isValid()) + OS << " at " << Item->Source.File << ':' << Item->Source.Line << ':' + << Item->Source.Column; + OS << " (" << stableId(*Item) << ")"; + } else { + OS << "a query built from its obligations"; + } + OS << "\n"; + } + OS << "; replay: " << Solver << ' ' << Relative << "\n"; + OS << Options << Script; + + // Written whole under a temporary name, so that a reader never sees a + // part of it. + int FD = -1; + llvm::SmallString<256> Temporary; + if (std::error_code EC = llvm::sys::fs::createUniqueFile(Full + ".%%%%%%.tmp", + FD, Temporary)) { + recordError("cannot write " + Full.str().str() + ": " + EC.message()); + return; + } + { + llvm::raw_fd_ostream Out(FD, /*shouldClose=*/true); + Out << Text; + Out.close(); + if (Out.has_error()) { + recordError("cannot write " + Full.str().str() + ": " + + Out.error().message()); + Out.clear_error(); + llvm::sys::fs::remove(Temporary); + return; + } + } + if (std::error_code EC = llvm::sys::fs::rename(Temporary, Full)) { + recordError("cannot write " + Full.str().str() + ": " + EC.message()); + llvm::sys::fs::remove(Temporary); + return; + } + Path = std::string(Full); +} + +void QueryDump::finish(llvm::StringRef Answer, llvm::StringRef Commands) { + if (Path.empty()) + return; + std::error_code EC; + llvm::raw_fd_ostream Out(Path, EC, llvm::sys::fs::OF_Append); + if (!EC) { + Out << Commands << "; cpp-verify: " << Answer << "\n"; + Out.close(); + if (Out.has_error()) { + EC = Out.error(); + Out.clear_error(); + } + } + if (EC) + recordError("cannot write " + Path + ": " + EC.message()); + Path.clear(); +} From a2144bd2d743ca9247af742559d13d9fb852c91e Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 05:23:10 +0530 Subject: [PATCH 230/259] verify: Build QueryDump.cpp. --- clang/lib/Verify/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/lib/Verify/CMakeLists.txt b/clang/lib/Verify/CMakeLists.txt index 1856824bae..969753ae79 100644 --- a/clang/lib/Verify/CMakeLists.txt +++ b/clang/lib/Verify/CMakeLists.txt @@ -42,6 +42,7 @@ add_clang_library(clangVerify Backend/ObligationSimplify.cpp Backend/ObligationSerialization.cpp Backend/ProofCache.cpp + Backend/QueryDump.cpp Backend/ChildProcess.cpp Backend/CVC5Backend.cpp Backend/Z3Encode.cpp From 8e47bdb84c31a19a04a58bfe9703cfa1a199d163 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 05:23:11 +0530 Subject: [PATCH 231/259] verify: Record what a Z3 check solves for its dump. --- clang/lib/Verify/Backend/Z3Encode.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/clang/lib/Verify/Backend/Z3Encode.h b/clang/lib/Verify/Backend/Z3Encode.h index b64f9dd908..72bd047de4 100644 --- a/clang/lib/Verify/Backend/Z3Encode.h +++ b/clang/lib/Verify/Backend/Z3Encode.h @@ -73,6 +73,15 @@ class Z3Encoder { BackendTimes *Times = nullptr; bool SearchSlice = false; bool QuantifiedQuery = false; + /// What the checks solve, for --dump-smt2. + const ObligationModule *DumpModule = nullptr; + const LogicExpr *DumpQuery = nullptr; + /// The check is the rerun that profiles quantifier instances. + bool Profiling = false; + /// \p S as a standalone script: the options of its solver, as commands, + /// for a check of \p Ms milliseconds, then its assertions and the check. + std::pair dumpScript(z3::solver &S, + unsigned Ms) const; z3::solver freshSolver(); /// \p S.check() within \p Ms milliseconds (0: no limit), unknown at once /// after interrupt(). From 6a3bc763281b380ba76026d6c0d34baef0457cb7 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 05:23:11 +0530 Subject: [PATCH 232/259] verify: Dump each Z3 check with its solver options and answer. --- clang/lib/Verify/Backend/Z3Encode.cpp | 47 +++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/clang/lib/Verify/Backend/Z3Encode.cpp b/clang/lib/Verify/Backend/Z3Encode.cpp index 4fe90ef463..b9bee5bd56 100644 --- a/clang/lib/Verify/Backend/Z3Encode.cpp +++ b/clang/lib/Verify/Backend/Z3Encode.cpp @@ -3,6 +3,7 @@ #include "ExtremeSearch.h" #include "ObligationSerialization.h" #include "ObligationSimplify.h" +#include "QueryDump.h" #include "TaskGroup.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/ScopeExit.h" @@ -1628,7 +1629,9 @@ Z3Encoder::profileQuantifiers(const z3::expr_vector &Assertions) { Rerun.set(Params); for (unsigned I = 0; I != Assertions.size(); ++I) Rerun.add(Assertions[I]); + Profiling = true; (void)check(Rerun, TimeoutMs == 0 ? 10000U : std::min(TimeoutMs, 10000U)); + Profiling = false; } std::cerr.flush(); std::fflush(stderr); @@ -1856,6 +1859,16 @@ z3::check_result Z3Encoder::check(z3::solver &S, unsigned Ms) { bool Interrupted = false; bool OverLimit = false; z3::check_result Result = z3::unknown; + QueryDump Dump; + if (queryDumpEnabled()) { + unsigned Major = 0, Minor = 0, Build = 0, Revision = 0; + Z3_get_version(&Major, &Minor, &Build, &Revision); + auto [Options, Script] = dumpScript(S, Ms); + Dump.start(DumpModule, DumpQuery, "z3", + std::to_string(Major) + "." + std::to_string(Minor) + "." + + std::to_string(Build), + Options, Script); + } std::thread Watchdog([&] { std::unique_lock Lock(CheckLock); const auto Limit = @@ -1893,9 +1906,41 @@ z3::check_result Z3Encoder::check(z3::solver &S, unsigned Ms) { OutOfMemory = true; }); Result = S.check(); + Dump.finish(Result == z3::sat ? "sat" + : Result == z3::unsat ? "unsat" + : "unknown (" + S.reason_unknown() + ")", + Result == z3::sat ? "(get-model)\n" : ""); return Result; } +std::pair Z3Encoder::dumpScript(z3::solver &S, + unsigned Ms) const { + // The settings freshSolver gives a query's solver, and the profiling + // rerun's own. + std::string Options; + const unsigned Timeout = Ms != 0 ? Ms : TimeoutMs; + if (Timeout != 0) + Options += "(set-option :timeout " + std::to_string(Timeout) + ")\n"; + if (Profiling) { + Options += "(set-option :smt.qi.profile true)\n"; + } else { + if (ResourceLimit != 0) + Options += "(set-option :rlimit " + std::to_string(ResourceLimit) + ")\n"; + Options += "(set-option :smt.mbqi true)\n" + "(set-option :smt.qi.eager_threshold 0.0)\n"; + } + // The solver's own printer: unlike the benchmark printer (to_smt2), it + // quotes symbols that are not SMT-LIB symbols, such as the ids + // `q@line:col` of quantifiers. + std::string Script = Z3_solver_to_string(Ctx, S); + if (!Script.empty() && Script.back() != '\n') + Script += '\n'; + // A quantified query's solver is the smt tactic's. + Script += QuantifiedQuery || Profiling ? "(check-sat-using smt)\n" + : "(check-sat)\n"; + return {Options, Script}; +} + std::optional Z3Encoder::encodeModuleAs(const ObligationModule &Module, const LogicExpr *Query, VerifyResult &Result) { @@ -3234,6 +3279,8 @@ VerifyResult Z3Encoder::decideModule(const ObligationModule &Module, std::optional TraceEventCount) { VerifyResult Out; QueryStart = std::chrono::steady_clock::now(); + DumpModule = &Module; + DumpQuery = Query; // A step toward settling another module wants a proof or a certified // counterexample within its slice: no domain probing, whose thousands of // ground instances can keep the solver from noticing its timeout. From 12156e1d91157b99f0b7bf1e0453e87ca1b9fd9a Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 05:23:12 +0530 Subject: [PATCH 233/259] verify: Dump each cvc5 run with its options as commands. --- clang/lib/Verify/Backend/CVC5Backend.cpp | 35 ++++++++++++++++++++---- 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/clang/lib/Verify/Backend/CVC5Backend.cpp b/clang/lib/Verify/Backend/CVC5Backend.cpp index 27745843f0..97b8b78add 100644 --- a/clang/lib/Verify/Backend/CVC5Backend.cpp +++ b/clang/lib/Verify/Backend/CVC5Backend.cpp @@ -4,6 +4,7 @@ #include "ChildProcess.h" #include "ObligationSerialization.h" #include "ObligationSimplify.h" +#include "QueryDump.h" #include "TaskGroup.h" #include "llvm/ADT/APInt.h" #include "llvm/ADT/STLFunctionalExtras.h" @@ -2406,6 +2407,18 @@ static bool printsSequencesReversed(const std::string &SolverPath) { return Reversed; } +/// The options cvc5 runs with, as names and values; a flag has no value. +static std::vector> +cvc5Options(unsigned TimeoutMs, unsigned ResourceLimit) { + std::vector> Options = { + {"seed", "0"}, {"sat-random-seed", "0"}, {"dump-models", ""}}; + if (TimeoutMs != 0) + Options.push_back({"tlimit-per", std::to_string(TimeoutMs)}); + if (ResourceLimit != 0) + Options.push_back({"rlimit-per", std::to_string(ResourceLimit)}); + return Options; +} + static SolverRun runCVC5(const std::string &SolverPath, llvm::StringRef Script, unsigned TimeoutMs, unsigned ResourceLimit, uint64_t MemoryLimitMB, @@ -2452,12 +2465,9 @@ static SolverRun runCVC5(const std::string &SolverPath, llvm::StringRef Script, } llvm::FileRemover RemoveError(ErrorPath); - std::vector OwnedArgs = {SolverPath, "--lang=smt2", "--seed=0", - "--sat-random-seed=0", "--dump-models"}; - if (TimeoutMs != 0) - OwnedArgs.push_back("--tlimit-per=" + std::to_string(TimeoutMs)); - if (ResourceLimit != 0) - OwnedArgs.push_back("--rlimit-per=" + std::to_string(ResourceLimit)); + std::vector OwnedArgs = {SolverPath, "--lang=smt2"}; + for (const auto &[Name, Value] : cvc5Options(TimeoutMs, ResourceLimit)) + OwnedArgs.push_back("--" + Name + (Value.empty() ? "" : "=" + Value)); OwnedArgs.push_back(InputPath.str().str()); llvm::SmallVector Args; for (const std::string &Argument : OwnedArgs) @@ -2774,8 +2784,21 @@ CVC5VerifyBackend::verifyQuery(const ObligationModule &Module, } Budget = static_cast(Remaining); } + QueryDump Dump; + if (queryDumpEnabled()) { + // The command line's options as commands, so that `cvc5 FILE` runs + // the query as cpp-verify did. + std::string Options; + for (const auto &[Name, Value] : cvc5Options(Budget, ResourceLimit)) + Options += "(set-option :" + Name + " " + + (Value.empty() ? "true" : Value) + ")\n"; + Dump.start(&Module, Query, "cvc5", "at " + SolverPath, Options, *Script); + } SolverRun Run = runCVC5(SolverPath, *Script, Budget, ResourceLimit, MemoryLimitMB, &Cancelled); + Dump.finish( + Run.Output ? llvm::StringRef(*Run.Output).split('\n').first.trim().str() + : "no answer (" + Run.Failure.Message + ")"); auto giveUp = [&](llvm::StringRef Outcome) { RefinementDecision Exhausted = Refinement.exhausted(Outcome); Result.Reason = Exhausted.Reason; From 167efb4904bab23e28c75a3c9e52701729d8bf24 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 05:23:12 +0530 Subject: [PATCH 234/259] verify: Add --dump-smt2 to cpp-verify. --- clang/tools/cpp-verify/Main.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/clang/tools/cpp-verify/Main.cpp b/clang/tools/cpp-verify/Main.cpp index e06f5099b6..0960081591 100644 --- a/clang/tools/cpp-verify/Main.cpp +++ b/clang/tools/cpp-verify/Main.cpp @@ -3,6 +3,7 @@ #include "../../lib/Verify/Backend/ObligationSerialization.h" #include "../../lib/Verify/Backend/ObligationSimplify.h" #include "../../lib/Verify/Backend/ProofCache.h" +#include "../../lib/Verify/Backend/QueryDump.h" #include "../../lib/Verify/Backend/VerifyBackend.h" #include "Counterexample.h" #include "CppVerifyVersion.h" @@ -50,6 +51,12 @@ static cl::opt cl::value_desc("layers"), cl::ValueOptional, cl::cat(CppVerifyCategory)); +static cl::opt DumpSMT2( + "dump-smt2", + cl::desc("Write every query sent to a solver to this directory, as a " + "script the solver replays on its own"), + cl::value_desc("directory"), cl::cat(CppVerifyCategory)); + static cl::opt LowerOnly( "lower-only", cl::desc("Run through backend encoding without checking satisfiability"), @@ -440,6 +447,8 @@ static std::vector gArguments; /// Ends the run's output: in SARIF mode, the log of the records collected. static int finishOutput(int ExitCode) { + if (std::string Error = verify::queryDumpError(); !Error.empty()) + llvm::errs() << "warning: --dump-smt2: " << Error << "\n"; if (DiagnosticsFormat != OutputFormat::Sarif) return ExitCode; gRecordStream.flush(); @@ -1362,6 +1371,9 @@ int main(int argc, const char **argv) { CommonOptionsParser &OptionsParser = ExpectedParser.get(); if (!resolveOptions(!ObligationIn.empty())) return 1; + if (!DumpSMT2.empty()) + verify::setQueryDumpDirectory( + DumpSMT2, ("cpp-verify " + verify::releaseVersion()).str()); if (CheckContracts) return verify::checkContracts(OptionsParser.getSourcePathList(), llvm::outs()) != 0; From ae748ca3b7882a95c8560618bda24754b4a66cb8 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 05:23:12 +0530 Subject: [PATCH 235/259] cmake: Build the vendored Z3's shell for replaying dumped queries. --- clang/cmake/modules/CppVerifyZ3.cmake | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/clang/cmake/modules/CppVerifyZ3.cmake b/clang/cmake/modules/CppVerifyZ3.cmake index d8e3ee9af0..d0c3b5c787 100644 --- a/clang/cmake/modules/CppVerifyZ3.cmake +++ b/clang/cmake/modules/CppVerifyZ3.cmake @@ -85,7 +85,7 @@ function(cppverify_z3_build_external) -DCMAKE_INSTALL_PREFIX:PATH=${_install} -DCMAKE_POSITION_INDEPENDENT_CODE:BOOL=ON -DZ3_BUILD_LIBZ3_SHARED:BOOL=OFF - -DZ3_BUILD_EXECUTABLE:BOOL=OFF + -DZ3_BUILD_EXECUTABLE:BOOL=ON -DZ3_BUILD_TEST_EXECUTABLES:BOOL=OFF -DZ3_BUILD_DOCUMENTATION:BOOL=OFF -DZ3_ENABLE_EXAMPLE_TARGETS:BOOL=OFF @@ -107,6 +107,9 @@ function(cppverify_z3_build_external) # sources include the headers must depend on this target as well. set_property(GLOBAL PROPERTY CPPVERIFY_Z3_EP_TARGET cppverify_z3_ep) set_property(GLOBAL PROPERTY CPPVERIFY_Z3_ORIGIN vendored) + # Z3's own shell, which replays the scripts --dump-smt2 writes in tests. + set_property(GLOBAL PROPERTY CPPVERIFY_Z3_SHELL + "${_install}/bin/z3${CMAKE_EXECUTABLE_SUFFIX}") endfunction() function(cppverify_z3_try_system out_var) @@ -143,6 +146,11 @@ function(cppverify_z3_try_system out_var) if(_target) message(STATUS "CppVerify: using system Z3 (${_target})") set_property(GLOBAL PROPERTY CPPVERIFY_Z3_ORIGIN system) + find_program(CPPVERIFY_SYSTEM_Z3_SHELL z3) + if(CPPVERIFY_SYSTEM_Z3_SHELL) + set_property(GLOBAL PROPERTY CPPVERIFY_Z3_SHELL + "${CPPVERIFY_SYSTEM_Z3_SHELL}") + endif() endif() set(${out_var} "${_target}" PARENT_SCOPE) endfunction() From 7af363bace820d8ce41739cb894305aec161f3af Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 05:23:13 +0530 Subject: [PATCH 236/259] test: Pass the Z3 shell to lit. --- clang/test/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/clang/test/CMakeLists.txt b/clang/test/CMakeLists.txt index e73e465d92..ba320d0c0b 100644 --- a/clang/test/CMakeLists.txt +++ b/clang/test/CMakeLists.txt @@ -49,6 +49,8 @@ if(LLVM_WITH_Z3 AND Z3_FOUND AND CMAKE_SYSTEM_NAME MATCHES "Linux") endif() endif() +get_property(CPPVERIFY_Z3_SHELL GLOBAL PROPERTY CPPVERIFY_Z3_SHELL) + configure_lit_site_cfg( ${CMAKE_CURRENT_SOURCE_DIR}/lit.site.cfg.py.in ${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg.py From 3257013ae3e4de16e40cdb35bf113fdc62fd39c7 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 05:23:13 +0530 Subject: [PATCH 237/259] test: Record the Z3 shell in the lit site config. --- clang/test/lit.site.cfg.py.in | 1 + 1 file changed, 1 insertion(+) diff --git a/clang/test/lit.site.cfg.py.in b/clang/test/lit.site.cfg.py.in index cb35118167..fd47295d88 100644 --- a/clang/test/lit.site.cfg.py.in +++ b/clang/test/lit.site.cfg.py.in @@ -26,6 +26,7 @@ config.clang_default_cxx_stdlib = "@CLANG_DEFAULT_CXX_STDLIB@" config.clang_staticanalyzer = @CLANG_ENABLE_STATIC_ANALYZER@ config.clang_staticanalyzer_z3 = @LLVM_WITH_Z3@ config.clang_staticanalyzer_z3_mock = @TEST_WITH_Z3_MOCK@ +config.cppverify_z3_shell = r"@CPPVERIFY_Z3_SHELL@" config.clang_enable_cir = @CLANG_ENABLE_CIR@ config.clang_examples = @CLANG_BUILD_EXAMPLES@ config.llvm_examples = @LLVM_INCLUDE_EXAMPLES@ From 38ef2f526a2a463c34ae9535788b74045b01b5a9 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 05:23:13 +0530 Subject: [PATCH 238/259] test: Add the z3-shell feature and the %cppverify-z3 substitution. --- clang/test/lit.cfg.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/clang/test/lit.cfg.py b/clang/test/lit.cfg.py index 077ccadd63..a350471cea 100644 --- a/clang/test/lit.cfg.py +++ b/clang/test/lit.cfg.py @@ -437,6 +437,11 @@ def calculate_arch_features(arch_string): if lit.util.which("cvc5", config.environment["PATH"]): config.available_features.add("cvc5") +# The Z3 shell of the Z3 cpp-verify links, for scripts cpp-verify writes. +if config.cppverify_z3_shell and os.path.exists(config.cppverify_z3_shell): + config.available_features.add("z3-shell") + config.substitutions.append(("%cppverify-z3", config.cppverify_z3_shell)) + if config.enable_backtrace: config.available_features.add("backtrace") From c2c1ed6d3ee59045fc4229768816dd8db4fd5496 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 05:23:14 +0530 Subject: [PATCH 239/259] test: Add replay_smt2.py, which replays dumped queries. --- clang/test/Verify/suite/Inputs/replay_smt2.py | 61 +++++++++++++++++++ 1 file changed, 61 insertions(+) create mode 100644 clang/test/Verify/suite/Inputs/replay_smt2.py diff --git a/clang/test/Verify/suite/Inputs/replay_smt2.py b/clang/test/Verify/suite/Inputs/replay_smt2.py new file mode 100644 index 0000000000..fc14b894be --- /dev/null +++ b/clang/test/Verify/suite/Inputs/replay_smt2.py @@ -0,0 +1,61 @@ +"""Replays the scripts --dump-smt2 wrote for one solver and compares each +answer with the one cpp-verify recorded. + +usage: replay_smt2.py SOLVER EXECUTABLE DIRECTORY + replay_smt2.py --list DIRECTORY + +Prints one line per script whose replay differs (an error, or another +answer to a script cpp-verify answered sat or unsat), then a summary line. +""" +import os +import subprocess +import sys + +if sys.argv[1] == "--list": + # The files, relative to the directory, in order. + for root, _, names in sorted(os.walk(sys.argv[2])): + for name in sorted(names): + print(os.path.relpath(os.path.join(root, name), sys.argv[2]) + .replace(os.sep, "/")) + sys.exit(0) + +solver, executable, directory = sys.argv[1:4] +scripts = sorted( + os.path.join(root, name) + for root, _, names in os.walk(directory) + for name in names + if name.endswith(".smt2") and ".%s-" % solver in name +) +compared = differing = 0 +for path in scripts: + with open(path) as f: + recorded = [l for l in f if l.startswith("; cpp-verify: ")] + answer = recorded[-1][len("; cpp-verify: ") :].strip() if recorded else "" + # A script cpp-verify did not settle is only read, for errors, not + # solved again to its timeout. + try: + output = subprocess.run( + [executable, path], stdout=subprocess.PIPE, + stderr=subprocess.STDOUT, universal_newlines=True, + timeout=None if answer in ("sat", "unsat") else 5, + ).stdout + except subprocess.TimeoutExpired as stopped: + output = stopped.output or "" + if isinstance(output, bytes): + output = output.decode(errors="replace") + lines = output.splitlines() + first = lines[0].strip() if lines else "" + relative = os.path.relpath(path, directory).replace(os.sep, "/") + if any(l.startswith("(error") for l in lines): + differing += 1 + error = next(l for l in lines if l.startswith("(error")) + print("%s: %s" % (relative, error)) + elif answer in ("sat", "unsat"): + compared += 1 + if first != answer: + differing += 1 + print("%s: recorded %s, replayed %s" % (relative, answer, first)) +print( + "%s: %d scripts, %d with a recorded sat or unsat, %d differing" + % (solver, len(scripts), compared, differing) +) From cec1a66947bb0d54c64cc97f8c2bed91d9a924da Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 05:23:14 +0530 Subject: [PATCH 240/259] test: Add the input of smt2_dumps.test. --- clang/test/Verify/suite/Inputs/smt2_dumps.cpp | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 clang/test/Verify/suite/Inputs/smt2_dumps.cpp diff --git a/clang/test/Verify/suite/Inputs/smt2_dumps.cpp b/clang/test/Verify/suite/Inputs/smt2_dumps.cpp new file mode 100644 index 0000000000..ba29c65208 --- /dev/null +++ b/clang/test/Verify/suite/Inputs/smt2_dumps.cpp @@ -0,0 +1,42 @@ +// Queries for smt2_dumps.test: a proof, a failure, a proof whose query has +// a quantifier, and a failure about a recursive spec, whose queries are +// checked again with definition instances. + +namespace cv = cppverify; + +int inc(int x) + cv::pre(x < 100) + cv::post(cv::result == x + 1) +{ + return x + 1; +} + +int clamp(int x) + cv::pre(x > -100 && x < 100) + cv::post(cv::result >= 0) +{ + if (x < 0) + return x + 1; + return x; +} + +int second(const int *a, int n) + cv::pre(cv::valid(a, n) && n > 2) + cv::pre(cv::forall(k, 0, n, a[k] >= 0)) + cv::post(cv::result >= 0) +{ + return a[1]; +} + +cppverify::spec int tri(int n) + cv::decreases(n) +{ + return n <= 0 ? 0 : tri(n - 1) + n; +} + +int closed(int n) + cv::pre(0 <= n && n <= 3) + cv::post(cv::result == tri(n)) +{ + return n; +} From c1e2be358fed8fe384d535e6f52b5dad61bcc6ba Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 05:23:15 +0530 Subject: [PATCH 241/259] test: Check --dump-smt2 in smt2_dumps.test. --- clang/test/Verify/suite/smt2_dumps.test | 101 ++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 clang/test/Verify/suite/smt2_dumps.test diff --git a/clang/test/Verify/suite/smt2_dumps.test b/clang/test/Verify/suite/smt2_dumps.test new file mode 100644 index 0000000000..3a69a62707 --- /dev/null +++ b/clang/test/Verify/suite/smt2_dumps.test @@ -0,0 +1,101 @@ +# --dump-smt2 writes each query a solver checks as a script the solver +# replays on its own: the options cpp-verify sets, the query, the check, and +# the answer cpp-verify got. Names depend on the query alone. +# +# RUN: rm -rf %t && mkdir -p %t +# RUN: not %cpp-verify --jobs=1 --dump-smt2=%t/z3 %S/Inputs/smt2_dumps.cpp -- 2>&1 \ +# RUN: | FileCheck %s --check-prefix=VERDICTS +# RUN: %python %S/Inputs/replay_smt2.py --list %t/z3 > %t/z3.files +# RUN: FileCheck %s --check-prefix=FILES --input-file=%t/z3.files +# RUN: cat %t/z3/clamp-*/postcondition-16-23.z3-*.smt2 | FileCheck %s --check-prefix=FAILED +# RUN: cat %t/z3/second-*/whole.z3-*.smt2 | FileCheck %s --check-prefix=QUANTIFIED +# +# A second run writes the same files. +# RUN: not %cpp-verify --jobs=1 --dump-smt2=%t/again %S/Inputs/smt2_dumps.cpp -- > /dev/null 2>&1 +# RUN: %python %S/Inputs/replay_smt2.py --list %t/again > %t/again.files +# RUN: diff %t/z3.files %t/again.files +# +# Each script replays in Z3's own shell with the answer cpp-verify got, and +# in cvc5 likewise. +# RUN: %if z3-shell %{ %python %S/Inputs/replay_smt2.py z3 %cppverify-z3 %t/z3 | FileCheck %s --check-prefix=Z3 %} +# RUN: %if cvc5 %{ not %cpp-verify --jobs=1 --backend=cvc5 --dump-smt2=%t/cvc5 %S/Inputs/smt2_dumps.cpp -- > /dev/null 2>&1 %} +# RUN: %if cvc5 %{ cat %t/cvc5/clamp-*/postcondition-16-23.cvc5-*.smt2 | FileCheck %s --check-prefix=CVC5 %} +# RUN: %if cvc5 %{ %python %S/Inputs/replay_smt2.py cvc5 cvc5 %t/cvc5 | FileCheck %s --check-prefix=CVC5-REPLAY %} +# +# An archive's replay writes the queries it checks. +# RUN: not %cpp-verify --jobs=1 --obligation-out=%t/q.cpv %S/Inputs/smt2_dumps.cpp -- > /dev/null 2>&1 +# RUN: not %cpp-verify --jobs=1 --obligation-in=%t/q.cpv --dump-smt2=%t/replay > /dev/null 2>&1 +# RUN: %python %S/Inputs/replay_smt2.py --list %t/replay | FileCheck %s --check-prefix=REPLAY +# +# A directory that cannot be written is a warning; the verdicts stand. +# RUN: touch %t/plain +# RUN: not %cpp-verify --jobs=1 --dump-smt2=%t/plain %S/Inputs/smt2_dumps.cpp -- 2>&1 \ +# RUN: | FileCheck %s --check-prefix=UNWRITABLE + +VERDICTS: Verified: inc [backend=z3] +VERDICTS: error: verification failed: clamp [postcondition] +VERDICTS: Verified: second [backend=z3] +VERDICTS: error: verification failed: closed [postcondition] + +A function's queries are in a directory named by the function and its +identity, each by its obligation and its script; the vacuity and contract +checks have their own. +FILES: clamp-[[CLAMP:[0-9a-f]+]]/missing-return-18-3.z3-{{[0-9a-f]+}}.smt2 +FILES-NEXT: clamp-[[CLAMP]]/overflow-19-5.z3-{{[0-9a-f]+}}.smt2 +FILES-NEXT: clamp-[[CLAMP]]/postcondition-16-23.z3-{{[0-9a-f]+}}.smt2 +FILES-NEXT: clamp-[[CLAMP]]/whole.z3-{{[0-9a-f]+}}.smt2 +A query checked again, with the definition instances the certifier asked +for, is a file for each check. +FILES-NEXT: closed-[[CLOSED:[0-9a-f]+]]/missing-return-synthetic.z3-{{[0-9a-f]+}}.smt2 +FILES-NEXT: closed-[[CLOSED]]/postcondition-39-23.z3-{{[0-9a-f]+}}.smt2 +FILES-NEXT: closed-[[CLOSED]]/postcondition-39-23.z3-{{[0-9a-f]+}}.smt2 +FILES: closed-[[CLOSED]]/whole.z3-{{[0-9a-f]+}}.smt2 +FILES-NEXT: closed-[[CLOSED]]/whole.z3-{{[0-9a-f]+}}.smt2 +FILES: inc-{{[0-9a-f]+}}/whole.z3-{{[0-9a-f]+}}.smt2 +FILES-NEXT: inc_smoke-{{[0-9a-f]+}}/whole.z3-{{[0-9a-f]+}}.smt2 +FILES-NEXT: second-{{[0-9a-f]+}}/whole.z3-{{[0-9a-f]+}}.smt2 +FILES-NEXT: second_contract-{{[0-9a-f]+}}/whole.z3-{{[0-9a-f]+}}.smt2 +FILES-NEXT: second_smoke-{{[0-9a-f]+}}/whole.z3-{{[0-9a-f]+}}.smt2 +FILES-NEXT: tri_decreases-{{[0-9a-f]+}}/whole.z3-{{[0-9a-f]+}}.smt2 +FILES-NOT: {{.}} + +FAILED: ; cpp-verify {{.*}}, z3 {{[0-9]+\.[0-9]+\.[0-9]+}} +FAILED-NEXT: ; clamp: the postcondition check at {{.*}}smt2_dumps.cpp:16:23 ({{.*}}::postcondition@16:23) +FAILED-NEXT: ; replay: z3 clamp-{{[0-9a-f]+}}{{[/\\]}}postcondition-16-23.z3-{{[0-9a-f]+}}.smt2 +FAILED-NEXT: (set-option :timeout 30000) +FAILED-NEXT: (set-option :rlimit 6000000) +FAILED-NEXT: (set-option :smt.mbqi true) +FAILED-NEXT: (set-option :smt.qi.eager_threshold 0.0) +FAILED: (declare-fun x_0 () Int) +FAILED: (check-sat) +FAILED-NEXT: (get-model) +FAILED-NEXT: ; cpp-verify: sat +FAILED-NOT: {{.}} + +A quantified query is solved by the smt tactic. +QUANTIFIED: ; second: every obligation at once +QUANTIFIED: (check-sat-using smt) +QUANTIFIED-NEXT: ; cpp-verify: unsat + +Z3: z3: {{[0-9]+}} scripts, {{[0-9]+}} with a recorded sat or unsat, 0 differing + +cvc5's command-line options are commands of the script. +CVC5: ; cpp-verify {{.*}}, cvc5 at {{.*}} +CVC5-NEXT: ; clamp: the postcondition check at {{.*}}smt2_dumps.cpp:16:23 +CVC5-NEXT: ; replay: cvc5 clamp-{{[0-9a-f]+}}{{[/\\]}}postcondition-16-23.cvc5-{{[0-9a-f]+}}.smt2 +CVC5-NEXT: (set-option :seed 0) +CVC5-NEXT: (set-option :sat-random-seed 0) +CVC5-NEXT: (set-option :dump-models true) +CVC5-NEXT: (set-option :tlimit-per 30000) +CVC5-NEXT: (set-logic ALL) +CVC5: (check-sat) +CVC5-NEXT: (exit) +CVC5-NEXT: ; cpp-verify: sat + +CVC5-REPLAY: cvc5: {{[0-9]+}} scripts, {{[0-9]+}} with a recorded sat or unsat, 0 differing + +REPLAY: clamp-{{[0-9a-f]+}}/whole.z3-{{[0-9a-f]+}}.smt2 + +UNWRITABLE: Verified: inc [backend=z3] +UNWRITABLE: warning: --dump-smt2: cannot create {{.*}}plain{{.*}} +UNWRITABLE: Summary: 3 verified, 2 failed From 0e5d7cdacea59e2031cf1f448f4e24172dbe3d9e Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 05:23:15 +0530 Subject: [PATCH 242/259] docs: Document --dump-smt2 in tooling. --- website/source/language/tooling.rst | 94 +++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/website/source/language/tooling.rst b/website/source/language/tooling.rst index d4a28cd418..c9045aca52 100644 --- a/website/source/language/tooling.rst +++ b/website/source/language/tooling.rst @@ -718,6 +718,9 @@ Backends canonical Obligation IR construction, spec-axiom encoding, and selected Z3/SMT-LIB translation without calling a solver. Supported for Z3, cvc5, portfolio, and BMC. + * - ``--dump-smt2=DIR`` + - Write every query sent to Z3 or cvc5 to ``DIR``, each as a script the + solver replays on its own (see `Solver queries as scripts`_). * - ``--obligation-out=FILE`` - Write deterministic, versioned backend-neutral modules with portable source attribution and SHA-256 semantic identities. Multiple modules are @@ -760,6 +763,97 @@ reused across prefixes. JSON uses ``bound``, ``explored_bounds``, and ``reused_queries``. Lean generation reports ``Exported``. Only the pinned, admission-free kernel workflow reports ``Certified``. +Solver queries as scripts +------------------------- + +``--dump-smt2=DIR`` writes each query cpp-verify sends to a solver as an +SMT-LIB script that the solver runs on its own: ``z3 FILE`` or ``cvc5 +FILE``, with no other flags. Such a file is what a solver's bug report +needs, what compares two solver versions on the same query, and what shows +the exact formula behind a verdict. On ``clamp.cpp`` (from +:doc:`../book/part-ii/ch17-backends-modular-calls`): + +.. code-block:: text + + $ cpp-verify --dump-smt2=queries clamp.cpp + ... + $ find queries -type f | sort + queries/clamp-14e9c9/missing-return-7-3.z3-c326aaab.smt2 + queries/clamp-14e9c9/overflow-8-5.z3-19b38e3e.smt2 + queries/clamp-14e9c9/postcondition-5-23.z3-d86b7e26.smt2 + queries/clamp-14e9c9/whole.z3-3a4644f7.smt2 + +A function's queries are in a directory named by the function and the start +of the SHA-256 hash of its identity, so overloads stay apart; each file is +named by its obligation (``postcondition-5-23``, the postcondition at line 5, +column 23), or ``whole`` for every obligation at once, then the solver and +the start of the hash of the script itself. A name depends only on the query, +so the same query is the same file in every run, and two checks of one +obligation (a refinement round after the first check, say) are two files. +A check that cpp-verify adds is named after the function and the check, +every character but a letter, a digit, or ``_`` made ``_``: ``f_smoke`` +holds the vacuity checks of ``f``, and ``f_decreases`` the termination check +of a spec ``f``. + +A file starts with comments that say what it is, then the options cpp-verify +gives the solver, as commands, then the query and its check. After the check +come ``(get-model)`` when the answer was ``sat``, and the answer cpp-verify +got: + +.. code-block:: text + + ; cpp-verify 0.2.0-dev, z3 4.13.4 + ; clamp: the postcondition check at clamp.cpp:5:23 (fn_5f5a35636c616d7069::postcondition@5:23) + ; replay: z3 clamp-14e9c9/postcondition-5-23.z3-d86b7e26.smt2 + (set-option :timeout 30000) + (set-option :rlimit 6000000) + (set-option :smt.mbqi true) + (set-option :smt.qi.eager_threshold 0.0) + (declare-fun __result_1 () Int) + (declare-fun x_0 () Int) + ... + (check-sat) + (get-model) + ; cpp-verify: sat + +.. code-block:: text + + $ cd queries && z3 clamp-14e9c9/postcondition-5-23.z3-d86b7e26.smt2 + sat + ( + (define-fun __result_1 () Int + (- 1)) + ... + (define-fun x_0 () Int + (- 2)) + ) + +- **Which queries.** Every check a solver makes: the whole query and each + obligation's, every refinement round, the probes of a bounded domain, the + native-definition pass, the inductions, the confirmations, the vacuity and + contract checks, and the queries of an archive's replay. A query is + written before its check, so one that never returns still leaves its + file, and the answer is appended when the check ends: ``sat``, ``unsat``, + ``unknown`` with Z3's reason (``unknown (timeout)``), or, for cvc5, ``no + answer`` with what went wrong. ``--lower-only`` checks nothing, so it + writes nothing, and Lean writes its own project. +- **Options.** For Z3, the time the check was given (``:timeout``, which + can be less than ``--timeout`` for a check late in a query's budget), the + resource limit, and the quantifier settings, and ``(check-sat-using smt)`` + where cpp-verify solves a quantified query with the ``smt`` tactic. For + cvc5, its command-line options (``--seed=0``, ``--tlimit-per=N``, ...) as + ``(set-option ...)`` commands. +- **Replaying.** ``z3 FILE`` with the version in the first line (``z3 + --version``; cpp-verify links Z3 4.13.4) and ``cvc5 FILE`` give the answer + cpp-verify got for most queries. Z3's search on a quantified query depends + on the order in which its terms were created, and a replay creates them + as it reads the file, in another order than cpp-verify did, so such a + query can end differently, typically ``unknown`` where cpp-verify got an + answer. +- **Errors.** A directory that cannot be written is a warning at the end of + the run (``warning: --dump-smt2: cannot create ...``); verdicts do not + change. + Time limits ----------- From cebeebabb41b05ea43f3179a2f7624da5ecfbae7 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 05:23:15 +0530 Subject: [PATCH 243/259] docs: Point solver bug reports to --dump-smt2 in chapter 16. --- .../source/book/part-ii/ch16-when-verification-fails.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/website/source/book/part-ii/ch16-when-verification-fails.rst b/website/source/book/part-ii/ch16-when-verification-fails.rst index 6d96cc7749..89dadd2b37 100644 --- a/website/source/book/part-ii/ch16-when-verification-fails.rst +++ b/website/source/book/part-ii/ch16-when-verification-fails.rst @@ -163,6 +163,14 @@ true on the cycle, so no unfolding settles it, and a postcondition query or a fact the verifier gave it, which is a solver fault and says nothing about your program. +To report such a fault, or a query a solver takes too long on, to the +solver's developers, run with ``--dump-smt2=DIR``: every query is written to +``DIR`` as a script that ``z3 FILE`` or ``cvc5 FILE`` runs on its own, named +by the function and the obligation (``clamp-14e9c9/postcondition-5-23...``), +and ending with the answer cpp-verify got (see +:doc:`../../language/tooling`). The file is the report: it needs neither +cpp-verify nor your source. + Every reason code at a glance ----------------------------- From 5dd9fb35c0f862c00fb249e2e3a25188f572ae6a Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 05:23:16 +0530 Subject: [PATCH 244/259] docs: List --dump-smt2 in chapter 15. --- website/source/book/part-ii/ch15-toolchain-and-flags.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/website/source/book/part-ii/ch15-toolchain-and-flags.rst b/website/source/book/part-ii/ch15-toolchain-and-flags.rst index 540821a878..76e60dc614 100644 --- a/website/source/book/part-ii/ch15-toolchain-and-flags.rst +++ b/website/source/book/part-ii/ch15-toolchain-and-flags.rst @@ -120,6 +120,8 @@ Other flags - ``cpp-verify --dump-ir[=1,2,3,4]`` — dump VCR / passive / Obligation IR / Z3 layers - ``cpp-verify --lower-only`` — construct and encode VCs without invoking Z3's satisfiability check +- ``cpp-verify --dump-smt2=DIR`` — write every query sent to Z3 or cvc5 as a + script the solver runs on its own, with the answer cpp-verify got - ``cpp-verify --obligation-out=FILE`` — write validated, versioned canonical obligation records with semantic hashes - ``cpp-verify --obligation-in=FILE`` — validate and replay records through Z3, From 4e34ff616e04e6a67289a67936c37e9c7007077c Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 05:23:16 +0530 Subject: [PATCH 245/259] docs: Note --dump-smt2 in the 0.2.0 release notes. --- website/source/release-notes.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/website/source/release-notes.rst b/website/source/release-notes.rst index 360ec40e87..5fc148b3b5 100644 --- a/website/source/release-notes.rst +++ b/website/source/release-notes.rst @@ -528,6 +528,15 @@ in text, JSON, SARIF, GitHub annotations, and archive replay, evaluated by the certifier in the checked model; the race's refutation states its values (:doc:`book/part-ii/ch17-backends-modular-calls`). +**Queries as SMT-LIB scripts.** The only view of a query was +``--dump-ir=4``, Z3 terms without declarations or a check, which no solver +reads. ``--dump-smt2=DIR`` writes every query cpp-verify sends to Z3 or cvc5 +as a script that ``z3 FILE`` or ``cvc5 FILE`` runs on its own: the options +cpp-verify gave the solver, as commands, the query, its check, and the +answer cpp-verify got, in a file named by the function and the obligation, +for solver bug reports and for comparing solver versions +(:doc:`language/tooling`). + **Counterexamples after a loop.** A failure whose counterexample passed through a loop looked like any other, though its state there came from the loop's invariants and no execution need reach it: the first loop most users From 357adee13600db57a13c8fccded014e547d4c5fd Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 05:23:16 +0530 Subject: [PATCH 246/259] docs: Describe the query dump in ARCHITECTURE. --- docs/ARCHITECTURE.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index ace0d0592c..2f5e1b35d8 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -3203,6 +3203,30 @@ encoding error remains a hard failure; success is reported as `Lowered`, never `Verified`. This is intentionally distinct from Clang's `-fno-verify`, which stops before VCR conversion. +`cpp-verify --dump-smt2=DIR` writes every query sent to a solver as a +standalone SMT-LIB script (`Backend/QueryDump.cpp`): Z3's checks all go +through `Z3Encoder::check`, which writes `Z3_solver_to_string` of the solver, +after the options `freshSolver` gave it as `set-option` commands and +followed by `(check-sat)`, or `(check-sat-using smt)` for a quantified query, +whose solver is the `smt` tactic's; Z3's benchmark printer (`to_smt2`) is not +used, since it leaves symbols such as the quantifier ids `q@line:col` +unquoted, which no parser reads. cvc5's checks go through `runCVC5`, and the +script it runs is written after its command-line options as `set-option` +commands (`cvc5Options` builds both). The script is written before the +check and the answer appended after it. A file is +`-
/.-.smt2`: the function's name made safe +for every file system and the start of the SHA-256 of its identity, the +obligation's stable id as `kind-line-col` (`whole` for the complete query), +and the start of the SHA-256 of the script, so a name depends only on the +query, as Frama-C keys its per-goal files and Verus its logs (Boogie's +`/proverLog` names by time), and the options are in the file, which Verus's +logs and Frama-C's files leave on the solver's command line. A replay builds +Z3's terms in another order than the encoder did, and Z3's search on a +quantified query depends on that order: the vacuity query of +`constructors.cpp`'s `Copy4` is `sat` in the encoder's context, and in a +fresh context, the API's or `z3`'s, the same assertions are `unknown` +(incomplete quantifiers). + ## Regression and Coverage - Tests: `clang/test/Verify/` (frontend) and `clang/test/Verify/suite/` From 8ac9bb21f957da925b23a25afff7107ee83f411e Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 05:23:17 +0530 Subject: [PATCH 247/259] docs: Mention --dump-smt2 in DESIGN. --- docs/DESIGN.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/DESIGN.md b/docs/DESIGN.md index a4a2a25c18..de23262499 100644 --- a/docs/DESIGN.md +++ b/docs/DESIGN.md @@ -2242,6 +2242,10 @@ logical-function declarations with compact step definitions and exact finite fuel levels. Layer 3 dumps this exact module; Layer 4 and ordinary verification encode the same in-memory object. There is no separate dump-only weakest-precondition implementation and no backend may borrow VCR declarations. +`--dump-smt2=DIR` writes each query a solver checks, as that solver received +it, as a standalone SMT-LIB script with the solver's options as commands and +the answer cpp-verify got, named by the function, the obligation, and a hash +of the script. Diagnostic metadata is non-semantic: names, source ranges, internal positional and public source-anchored IDs, and trace events survive archive replay but do From 92f6074c442407f340f6207b45d9db325fa8aed6 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 05:23:17 +0530 Subject: [PATCH 248/259] docs: Show --dump-smt2 in the README. --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 098bf5e3b3..edb0712e04 100644 --- a/README.md +++ b/README.md @@ -160,6 +160,7 @@ and `docs/UB-CHECKING.md`. ./build/bin/cpp-verify --diagnostics-format=sarif file.cpp # SARIF 2.1.0, for code scanning ./build/bin/cpp-verify --obligation-out=goals.cpv file.cpp # backend-neutral archive ./build/bin/cpp-verify --dump-ir=1,2,3,4 file.cpp # VCR, passive, Obligation IR, Z3 +./build/bin/cpp-verify --dump-smt2=queries file.cpp # each solver query as an SMT-LIB script ``` Z3 runs support deterministic isolated solving (`--jobs`) and positive-proof reuse From 74cac5053469bc2f484e0cfd7a8306fbcfb25fd9 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 05:29:42 +0530 Subject: [PATCH 249/259] test: Expect cppverify.diagnostic/2 records in obligation_size_limit.cpp. --- clang/test/Verify/suite/obligation_size_limit.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/obligation_size_limit.cpp b/clang/test/Verify/suite/obligation_size_limit.cpp index c3433e67df..ad7ebf4f63 100644 --- a/clang/test/Verify/suite/obligation_size_limit.cpp +++ b/clang/test/Verify/suite/obligation_size_limit.cpp @@ -58,7 +58,7 @@ int steps(int x) return y; } // LIMIT: obligation_size_limit.cpp:[[@LINE-22]]:5: Unresolved: steps [backend=z3] [reason=query.size-limit] (the proof obligations would take at least 747 expression nodes, more than the limit of 500 (--max-query-nodes): each check repeats every assumption before it, so split the function or raise the limit) -// JSON: {"backend":"z3","function":"steps","message":"steps [backend=z3] [reason=query.size-limit] (the proof obligations would take at least 747 expression nodes, more than the limit of 500 (--max-query-nodes): each check repeats every assumption before it, so split the function or raise the limit)","reason":"query.size-limit","schema":"cppverify.diagnostic/1","severity":"error","source":{"column":5,"end_column":5,"end_line":[[@LINE-23]],"file":"{{.*}}obligation_size_limit.cpp","line":[[@LINE-23]]},"status":"unresolved"} +// JSON: {"backend":"z3","function":"steps","function_source":{"column":5,"end_column":10,"end_line":[[@LINE-23]],"file":"{{.*}}obligation_size_limit.cpp","line":[[@LINE-23]]},"message":"steps [backend=z3] [reason=query.size-limit] (the proof obligations would take at least 747 expression nodes, more than the limit of 500 (--max-query-nodes): each check repeats every assumption before it, so split the function or raise the limit)","reason":"query.size-limit","schema":"cppverify.diagnostic/2","severity":"error","source":{"column":5,"end_column":10,"end_line":[[@LINE-23]],"file":"{{.*}}obligation_size_limit.cpp","line":[[@LINE-23]]},"status":"unresolved"} // LOWER: obligation_size_limit.cpp:[[@LINE-24]]:5: error: Z3 lowering failed: steps [backend=z3] [reason=query.size-limit] (the proof obligations would take at least 747 expression nodes, more than the limit of 500 // AT: Verified: steps [backend=z3] // SHARED: Verified: steps [backend=z3] @@ -74,7 +74,7 @@ int caller(int x) return y + 1; } // LIMIT: Unresolved: caller [backend=z3] [reason=callee.contract] (relies on the contract of steps, which is not established) -// JSON: {"backend":"z3","function":"caller","message":"caller [backend=z3] [reason=callee.contract] (relies on the contract of steps, which is not established)","reason":"callee.contract", +// JSON: {"backend":"z3","function":"caller","function_source":{"column":5,{{.*}}},"message":"caller [backend=z3] [reason=callee.contract] (relies on the contract of steps, which is not established)","reason":"callee.contract", // LOWER: Lowered: caller // AT: Verified: caller [backend=z3] // BELOW: Unresolved: caller [backend=z3] [reason=callee.contract] From 7d4958fe4b4c6f59d567057103177f297ff63102 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 05:36:03 +0530 Subject: [PATCH 250/259] test: Add overloads to the input of smt2_dumps.test. --- clang/test/Verify/suite/Inputs/smt2_dumps.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/clang/test/Verify/suite/Inputs/smt2_dumps.cpp b/clang/test/Verify/suite/Inputs/smt2_dumps.cpp index ba29c65208..df7b9a4fe8 100644 --- a/clang/test/Verify/suite/Inputs/smt2_dumps.cpp +++ b/clang/test/Verify/suite/Inputs/smt2_dumps.cpp @@ -40,3 +40,18 @@ int closed(int n) { return n; } + +// Overloads, whose queries are kept apart. +int half(int x) + cv::pre(x >= 0) + cv::post(cv::result <= x) +{ + return x / 2; +} + +long half(long x) + cv::pre(x >= 0) + cv::post(cv::result <= x) +{ + return x / 2; +} From 7fe2cf03d9ab68853f947875e17ae20cf84849d5 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 05:36:04 +0530 Subject: [PATCH 251/259] test: Check that overloads' queries are apart in smt2_dumps.test. --- clang/test/Verify/suite/smt2_dumps.test | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/smt2_dumps.test b/clang/test/Verify/suite/smt2_dumps.test index 3a69a62707..a67565e822 100644 --- a/clang/test/Verify/suite/smt2_dumps.test +++ b/clang/test/Verify/suite/smt2_dumps.test @@ -7,6 +7,8 @@ # RUN: | FileCheck %s --check-prefix=VERDICTS # RUN: %python %S/Inputs/replay_smt2.py --list %t/z3 > %t/z3.files # RUN: FileCheck %s --check-prefix=FILES --input-file=%t/z3.files +# RUN: %python -c "import os, sys; print(sorted(len(os.listdir(os.path.join(sys.argv[1], d))) > 0 for d in os.listdir(sys.argv[1]) if d.startswith('half-')))" %t/z3 \ +# RUN: | FileCheck %s --check-prefix=OVERLOADS # RUN: cat %t/z3/clamp-*/postcondition-16-23.z3-*.smt2 | FileCheck %s --check-prefix=FAILED # RUN: cat %t/z3/second-*/whole.z3-*.smt2 | FileCheck %s --check-prefix=QUANTIFIED # @@ -36,6 +38,8 @@ VERDICTS: Verified: inc [backend=z3] VERDICTS: error: verification failed: clamp [postcondition] VERDICTS: Verified: second [backend=z3] VERDICTS: error: verification failed: closed [postcondition] +VERDICTS: Verified: half [backend=z3] +VERDICTS: Verified: half [backend=z3] A function's queries are in a directory named by the function and its identity, each by its obligation and its script; the vacuity and contract @@ -51,7 +55,11 @@ FILES-NEXT: closed-[[CLOSED]]/postcondition-39-23.z3-{{[0-9a-f]+}}.smt2 FILES-NEXT: closed-[[CLOSED]]/postcondition-39-23.z3-{{[0-9a-f]+}}.smt2 FILES: closed-[[CLOSED]]/whole.z3-{{[0-9a-f]+}}.smt2 FILES-NEXT: closed-[[CLOSED]]/whole.z3-{{[0-9a-f]+}}.smt2 -FILES: inc-{{[0-9a-f]+}}/whole.z3-{{[0-9a-f]+}}.smt2 +FILES: half-{{[0-9a-f]+}}/whole.z3-{{[0-9a-f]+}}.smt2 +FILES-NEXT: half-{{[0-9a-f]+}}/whole.z3-{{[0-9a-f]+}}.smt2 +FILES-NEXT: half_smoke-{{[0-9a-f]+}}/whole.z3-{{[0-9a-f]+}}.smt2 +FILES-NEXT: half_smoke-{{[0-9a-f]+}}/whole.z3-{{[0-9a-f]+}}.smt2 +FILES-NEXT: inc-{{[0-9a-f]+}}/whole.z3-{{[0-9a-f]+}}.smt2 FILES-NEXT: inc_smoke-{{[0-9a-f]+}}/whole.z3-{{[0-9a-f]+}}.smt2 FILES-NEXT: second-{{[0-9a-f]+}}/whole.z3-{{[0-9a-f]+}}.smt2 FILES-NEXT: second_contract-{{[0-9a-f]+}}/whole.z3-{{[0-9a-f]+}}.smt2 @@ -72,6 +80,9 @@ FAILED-NEXT: (get-model) FAILED-NEXT: ; cpp-verify: sat FAILED-NOT: {{.}} +Each overload has a directory of its own: the hash is of its identity. +OVERLOADS: [True, True] + A quantified query is solved by the smt tactic. QUANTIFIED: ; second: every obligation at once QUANTIFIED: (check-sat-using smt) @@ -98,4 +109,4 @@ REPLAY: clamp-{{[0-9a-f]+}}/whole.z3-{{[0-9a-f]+}}.smt2 UNWRITABLE: Verified: inc [backend=z3] UNWRITABLE: warning: --dump-smt2: cannot create {{.*}}plain{{.*}} -UNWRITABLE: Summary: 3 verified, 2 failed +UNWRITABLE: Summary: 5 verified, 2 failed From 664e5bc54c3ee9f8a1d21fd21d3e9bde9eaee711 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 05:41:35 +0530 Subject: [PATCH 252/259] test: Only read, without their checks, the dumped scripts cpp-verify did not settle. --- clang/test/Verify/suite/Inputs/replay_smt2.py | 22 ++++++++++++------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/clang/test/Verify/suite/Inputs/replay_smt2.py b/clang/test/Verify/suite/Inputs/replay_smt2.py index fc14b894be..e2a12d48ed 100644 --- a/clang/test/Verify/suite/Inputs/replay_smt2.py +++ b/clang/test/Verify/suite/Inputs/replay_smt2.py @@ -10,6 +10,7 @@ import os import subprocess import sys +import tempfile if sys.argv[1] == "--list": # The files, relative to the directory, in order. @@ -31,18 +32,23 @@ with open(path) as f: recorded = [l for l in f if l.startswith("; cpp-verify: ")] answer = recorded[-1][len("; cpp-verify: ") :].strip() if recorded else "" - # A script cpp-verify did not settle is only read, for errors, not - # solved again to its timeout. + # A script cpp-verify did not settle is only read, for errors: its + # checks are left out, so that it is not solved again to its timeout. + run = path + if answer not in ("sat", "unsat"): + with open(path) as f: + text = "".join(l for l in f if not l.startswith(("(check-sat", "(get-model"))) + handle, run = tempfile.mkstemp(suffix=".smt2") + with os.fdopen(handle, "w") as f: + f.write(text) try: output = subprocess.run( - [executable, path], stdout=subprocess.PIPE, + [executable, run], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, universal_newlines=True, - timeout=None if answer in ("sat", "unsat") else 5, ).stdout - except subprocess.TimeoutExpired as stopped: - output = stopped.output or "" - if isinstance(output, bytes): - output = output.decode(errors="replace") + finally: + if run != path: + os.remove(run) lines = output.splitlines() first = lines[0].strip() if lines else "" relative = os.path.relpath(path, directory).replace(os.sep, "/") From 6d937ebd6c1d9ecc92affe01d81d141357c20414 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 06:14:37 +0530 Subject: [PATCH 253/259] verify: Dump a solver of the checked assertions alone, without the model converter. --- clang/lib/Verify/Backend/Z3Encode.cpp | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/clang/lib/Verify/Backend/Z3Encode.cpp b/clang/lib/Verify/Backend/Z3Encode.cpp index b9bee5bd56..56ffd0eba8 100644 --- a/clang/lib/Verify/Backend/Z3Encode.cpp +++ b/clang/lib/Verify/Backend/Z3Encode.cpp @@ -1914,7 +1914,7 @@ z3::check_result Z3Encoder::check(z3::solver &S, unsigned Ms) { } std::pair Z3Encoder::dumpScript(z3::solver &S, - unsigned Ms) const { + unsigned Ms) { // The settings freshSolver gives a query's solver, and the profiling // rerun's own. std::string Options; @@ -1931,8 +1931,14 @@ std::pair Z3Encoder::dumpScript(z3::solver &S, } // The solver's own printer: unlike the benchmark printer (to_smt2), it // quotes symbols that are not SMT-LIB symbols, such as the ids - // `q@line:col` of quantifiers. - std::string Script = Z3_solver_to_string(Ctx, S); + // `q@line:col` of quantifiers. A solver that has checked before also + // prints the model converter its preprocessing left (`model-add` of + // symbols it never declares), so a solver of the assertions alone prints + // the query. + z3::solver Assertions(Ctx); + for (const z3::expr &Assertion : S.assertions()) + Assertions.add(Assertion); + std::string Script = Z3_solver_to_string(Ctx, Assertions); if (!Script.empty() && Script.back() != '\n') Script += '\n'; // A quantified query's solver is the smt tactic's. From 31150f5f3ee6b0a41990cb6e069de5cc9d171c21 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 06:14:37 +0530 Subject: [PATCH 254/259] verify: Let dumpScript build a solver. --- clang/lib/Verify/Backend/Z3Encode.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/clang/lib/Verify/Backend/Z3Encode.h b/clang/lib/Verify/Backend/Z3Encode.h index 72bd047de4..7afef37aee 100644 --- a/clang/lib/Verify/Backend/Z3Encode.h +++ b/clang/lib/Verify/Backend/Z3Encode.h @@ -80,8 +80,7 @@ class Z3Encoder { bool Profiling = false; /// \p S as a standalone script: the options of its solver, as commands, /// for a check of \p Ms milliseconds, then its assertions and the check. - std::pair dumpScript(z3::solver &S, - unsigned Ms) const; + std::pair dumpScript(z3::solver &S, unsigned Ms); z3::solver freshSolver(); /// \p S.check() within \p Ms milliseconds (0: no limit), unknown at once /// after interrupt(). From 7736262214a50032a2c2c6455f1ee9267a21a850 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 06:14:38 +0530 Subject: [PATCH 255/259] docs: Say why the dump prints a solver of the assertions in ARCHITECTURE. --- docs/ARCHITECTURE.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index 2f5e1b35d8..bb223ec269 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -3205,8 +3205,11 @@ stops before VCR conversion. `cpp-verify --dump-smt2=DIR` writes every query sent to a solver as a standalone SMT-LIB script (`Backend/QueryDump.cpp`): Z3's checks all go -through `Z3Encoder::check`, which writes `Z3_solver_to_string` of the solver, -after the options `freshSolver` gave it as `set-option` commands and +through `Z3Encoder::check`, which writes `Z3_solver_to_string` of a solver +holding the checked solver's assertions (a solver that has checked before +also prints the model converter its preprocessing left, `model-add` of +symbols it never declares), after the options `freshSolver` gave it as +`set-option` commands and followed by `(check-sat)`, or `(check-sat-using smt)` for a quantified query, whose solver is the `smt` tactic's; Z3's benchmark printer (`to_smt2`) is not used, since it leaves symbols such as the quantifier ids `q@line:col` From ff9cd53ee12cf15a8825102097bd64ef4909d910 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 06:17:37 +0530 Subject: [PATCH 256/259] test: Add a query checked again on its solver for smt2_dumps.test. --- .../test/Verify/suite/Inputs/smt2_dumps_narrowed.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 clang/test/Verify/suite/Inputs/smt2_dumps_narrowed.cpp diff --git a/clang/test/Verify/suite/Inputs/smt2_dumps_narrowed.cpp b/clang/test/Verify/suite/Inputs/smt2_dumps_narrowed.cpp new file mode 100644 index 0000000000..45c50d6ae1 --- /dev/null +++ b/clang/test/Verify/suite/Inputs/smt2_dumps_narrowed.cpp @@ -0,0 +1,12 @@ +// For smt2_dumps.test: a counterexample whose quantifier range is too wide +// to check is sought again, on the same solver, with a narrower range. + +namespace cv = cppverify; + +int first_positive_bitwise(const int *p, int n) + cv::pre(n >= 2000000 && n <= 3000000 && cv::valid(p, n)) + cv::pre(cv::forall(i, 0, n, (i ^ 1431655765) < 0 || p[i] >= 0)) + cv::post(cv::result > 0) +{ + return p[0]; +} From 6bef7eb78b98569f6e7bc0d124fc572479771e7d Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 06:17:37 +0530 Subject: [PATCH 257/259] test: Check that a dump leaves out the model converter in smt2_dumps.test. --- clang/test/Verify/suite/smt2_dumps.test | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/clang/test/Verify/suite/smt2_dumps.test b/clang/test/Verify/suite/smt2_dumps.test index a67565e822..ae0a583c87 100644 --- a/clang/test/Verify/suite/smt2_dumps.test +++ b/clang/test/Verify/suite/smt2_dumps.test @@ -24,6 +24,13 @@ # RUN: %if cvc5 %{ cat %t/cvc5/clamp-*/postcondition-16-23.cvc5-*.smt2 | FileCheck %s --check-prefix=CVC5 %} # RUN: %if cvc5 %{ %python %S/Inputs/replay_smt2.py cvc5 cvc5 %t/cvc5 | FileCheck %s --check-prefix=CVC5-REPLAY %} # +# A solver that has checked before prints the model converter its +# preprocessing left, `model-add` of symbols it never declares; the dump of +# a later check on it leaves that out. +# RUN: not %cpp-verify --jobs=1 --dump-smt2=%t/narrowed %S/Inputs/smt2_dumps_narrowed.cpp -- > /dev/null 2>&1 +# RUN: cat %t/narrowed/first_positive_bitwise-*/postcondition-*.smt2 \ +# RUN: | FileCheck %s --check-prefix=NARROWED --implicit-check-not=model-add +# # An archive's replay writes the queries it checks. # RUN: not %cpp-verify --jobs=1 --obligation-out=%t/q.cpv %S/Inputs/smt2_dumps.cpp -- > /dev/null 2>&1 # RUN: not %cpp-verify --jobs=1 --obligation-in=%t/q.cpv --dump-smt2=%t/replay > /dev/null 2>&1 @@ -105,6 +112,9 @@ CVC5-NEXT: ; cpp-verify: sat CVC5-REPLAY: cvc5: {{[0-9]+}} scripts, {{[0-9]+}} with a recorded sat or unsat, 0 differing +NARROWED: (check-sat-using smt) +NARROWED: (check-sat-using smt) + REPLAY: clamp-{{[0-9a-f]+}}/whole.z3-{{[0-9a-f]+}}.smt2 UNWRITABLE: Verified: inc [backend=z3] From 98ff074b2cdd436ed68ab308c1e4a2d5732ab8f7 Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 15:01:58 +0530 Subject: [PATCH 258/259] test: Give confirmation_invariants.cpp's failure a budget a slow macOS runner can meet. --- clang/test/Verify/suite/confirmation_invariants.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/clang/test/Verify/suite/confirmation_invariants.cpp b/clang/test/Verify/suite/confirmation_invariants.cpp index 6900c3ccc6..071136de11 100644 --- a/clang/test/Verify/suite/confirmation_invariants.cpp +++ b/clang/test/Verify/suite/confirmation_invariants.cpp @@ -1,10 +1,13 @@ -// RUN: not %cpp-verify --jobs=4 --timeout=5000 --time-report %s -- 2>&1 | FileCheck %s +// RUN: not %cpp-verify --jobs=4 --timeout=20000 --time-report %s -- 2>&1 | FileCheck %s // // Unrolling drops the loops' invariants and measures, so a failure of one // has no copy at any bound: once the loops are unrolled once and no copy // has appeared, the search for an execution that fails it stops, instead of // solving every check at every bound until its time runs out (5.8 s at -// --timeout=5000 for this function, 30 s at the default 30000). +// --timeout=5000 for this function, 30 s at the default 30000). The time +// report shows the confirmation under a second; the budget leaves the +// failure itself time on a slow core (at --timeout=5000 a macOS runner timed +// out before finding it). namespace cv = cppverify; From 338f59500183830ee9e92715dd108aac655dcc5b Mon Sep 17 00:00:00 2001 From: SwayamInSync Date: Wed, 28 Oct 2026 15:01:59 +0530 Subject: [PATCH 259/259] test: Give extent_separation.cpp's decided run a budget a slow macOS runner can meet. --- clang/test/Verify/suite/extent_separation.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/clang/test/Verify/suite/extent_separation.cpp b/clang/test/Verify/suite/extent_separation.cpp index 6b8365b2d9..aab46d5965 100644 --- a/clang/test/Verify/suite/extent_separation.cpp +++ b/clang/test/Verify/suite/extent_separation.cpp @@ -1,5 +1,5 @@ // RUN: %clang -std=c++17 -fverify-contracts -fsyntax-only %s -// RUN: not %cpp-verify --check-ub %s -- 2>&1 | FileCheck %s --check-prefixes=CHECK,DECIDED +// RUN: not %cpp-verify --check-ub --timeout=120000 %s -- 2>&1 | FileCheck %s --check-prefixes=CHECK,DECIDED // RUN: not %cpp-verify --check-ub --int-encoding=bitvector --timeout=5000 %s -- 2>&1 | FileCheck %s --check-prefixes=CHECK,BV // RUN: %cpp-verify --check-ub --lower-only --dump-ir=1 %s -- 2>&1 | FileCheck %s --check-prefix=VCR // RUN: %cpp-verify --check-ub --lower-only --dump-ir=2 %s -- 2>&1 | FileCheck %s --check-prefix=PASSIVE @@ -51,8 +51,9 @@ void copy(const int *a, int *out, int n) // VCR-NEXT: post // A copy that writes zeros: its invariant fails where a holds anything else, -// which the solver finds at once (a reversed copy took 30 to 60 s, and on a -// slow runner timed out). +// which the solver finds in 1.7 s (3.6 s with one job; a reversed copy took +// 30 to 60 s). The first run's budget covers a slow runner, where the +// default 30 s once ran out. void wrong_copy(const int *a, int *out, int n) cppverify::pre(n >= 0 && valid(a, n) && valid(out, n)) cppverify::modifies(*out)