Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
106 commits
Select commit Hold shift + click to select a range
b41eba8
verify: Mark a function that uses a construct the verifier does not r…
SwayamInSync Oct 24, 2026
8966deb
verify: Copy the unsupported-construct mark with a function.
SwayamInSync Oct 24, 2026
d2c2979
verify: Keep the unsupported-construct mark through loop unrolling.
SwayamInSync Oct 24, 2026
7a44559
verify: Report a malformed inductive predicate with the predicate.
SwayamInSync Oct 24, 2026
219e435
verify: Name the predicate of each inductive predicate error.
SwayamInSync Oct 24, 2026
036a376
verify: Record the function and part of it each conversion error belo…
SwayamInSync Oct 24, 2026
a027243
verify: Keep what others may rely on of a function the verifier canno…
SwayamInSync Oct 24, 2026
5de19af
verify: Verify every function but those using a construct the verifie…
SwayamInSync Oct 24, 2026
f96eed0
test: Check the verdict that an unsupported construct's record carries.
SwayamInSync Oct 24, 2026
80eb0e4
test: Add the program of the per-function errors test.
SwayamInSync Oct 24, 2026
10dba84
test: Check that an unsupported construct costs its function alone.
SwayamInSync Oct 24, 2026
a24894d
docs: Say that an unsupported construct costs its function alone.
SwayamInSync Oct 24, 2026
94c24f4
docs: Describe failing closed per function in the limitations.
SwayamInSync Oct 24, 2026
6898ea4
docs: Extend construct.unsupported to whole functions in chapter 16.
SwayamInSync Oct 24, 2026
e176567
docs: Note that an unsupported construct costs its function alone in …
SwayamInSync Oct 24, 2026
7495172
docs: Describe per-function unsupported constructs in the design.
SwayamInSync Oct 24, 2026
faa6c01
docs: Describe per-function conversion errors in the architecture.
SwayamInSync Oct 24, 2026
e6bf536
verify: Keep only scalar reference parameters as footprints of one cell.
SwayamInSync Oct 24, 2026
69c1fcc
verify: Clone a function's scalar reference parameters.
SwayamInSync Oct 24, 2026
b504ed4
verify: Keep a function's scalar reference parameters through loop un…
SwayamInSync Oct 24, 2026
49ecde6
verify: Frame a record reference's footprint as its object, and name …
SwayamInSync Oct 24, 2026
7825fcb
verify: Declare the places and pointers reached through references to…
SwayamInSync Oct 24, 2026
959018e
verify: Verify records through references, as pointers never null or …
SwayamInSync Oct 24, 2026
6b05b73
test: Check records through references and members named whole in mod…
SwayamInSync Oct 24, 2026
1f3fedf
test: Stop expecting a reference to a record to be rejected.
SwayamInSync Oct 24, 2026
d906f99
docs: Describe records through references, with a checked example.
SwayamInSync Oct 24, 2026
a8b47d5
docs: Extend records and frames to references to records in chapter 14.
SwayamInSync Oct 24, 2026
a430f47
docs: List references to records as supported in the limitations.
SwayamInSync Oct 24, 2026
af65377
docs: Mention references to records on the front page.
SwayamInSync Oct 24, 2026
34b3ece
docs: Note records through references and members named whole in the …
SwayamInSync Oct 24, 2026
02e7fa7
docs: Describe records through references in the design.
SwayamInSync Oct 24, 2026
63b2b98
docs: Describe records through references in the architecture.
SwayamInSync Oct 24, 2026
c7f50c4
Merge branch 'fix/lean-refutations' into fix/per-function-errors.
SwayamInSync Oct 24, 2026
89d8e14
Merge branch 'fix/per-function-errors' into fix/record-references.
SwayamInSync Oct 24, 2026
61f543b
verify: Record the pointer and reference parameters that address a re…
SwayamInSync Oct 24, 2026
c132d06
verify: Clone a function's record parameters.
SwayamInSync Oct 24, 2026
98aced8
verify: Keep a function's record parameters through loop unrolling.
SwayamInSync Oct 24, 2026
9ff5f65
verify: Pass the address of a local to a pointer parameter, and recor…
SwayamInSync Oct 24, 2026
ced3b16
verify: Lend a local record to a callee that keeps no address of it, …
SwayamInSync Oct 24, 2026
64bd1d2
test: Check local records and addresses passed to callees.
SwayamInSync Oct 24, 2026
fbf6564
test: Expect a local record passed by reference to verify.
SwayamInSync Oct 24, 2026
2e87fff
docs: Describe local records passed to callees, with a checked example.
SwayamInSync Oct 24, 2026
d9595bb
docs: Extend reference arguments to local records and addresses in ch…
SwayamInSync Oct 24, 2026
4f6c7e1
docs: List local objects passed to callees as supported in the limita…
SwayamInSync Oct 24, 2026
efa9ef1
docs: Note local objects passed to callees in the release notes.
SwayamInSync Oct 24, 2026
3b4e989
docs: Describe local objects passed to callees in the design.
SwayamInSync Oct 24, 2026
90d335e
docs: Describe the record scan and the call's checks in the architect…
SwayamInSync Oct 24, 2026
d25912c
Merge branch 'fix/lean-refutations' into fix/per-function-errors.
SwayamInSync Oct 24, 2026
a504d1c
Merge branch 'fix/per-function-errors' into fix/record-references.
SwayamInSync Oct 24, 2026
3abd2bb
Merge branch 'fix/record-references' into fix/local-record-arguments.
SwayamInSync Oct 24, 2026
95908fc
verify: Record the parameters for the entry values of pointer fields …
SwayamInSync Oct 24, 2026
d2deea1
verify: Clone a function's field parameters.
SwayamInSync Oct 24, 2026
676ba99
verify: Keep a function's field parameters through loop unrolling.
SwayamInSync Oct 24, 2026
62811c3
verify: Declare the field extents a function's preconditions state.
SwayamInSync Oct 24, 2026
e14c7cb
verify: Give each pointer field with an extent a parameter for its en…
SwayamInSync Oct 24, 2026
24a857d
verify: Bind a field parameter to its field at entry and at every call.
SwayamInSync Oct 24, 2026
cc9bbcb
verify: Separate a pair with an extent over its extents alone.
SwayamInSync Oct 24, 2026
9f72e43
test: Check extents of pointer fields.
SwayamInSync Oct 24, 2026
5a1e930
test: Expect one separation of two extents at a call.
SwayamInSync Oct 24, 2026
265be83
docs: Describe extents of pointer fields, with a checked example.
SwayamInSync Oct 24, 2026
5d12760
docs: Extend the extent marker to pointer fields and state the separa…
SwayamInSync Oct 24, 2026
010f4f9
docs: Extend the extent marker to pointer fields in chapter 14.
SwayamInSync Oct 24, 2026
663d622
docs: Extend the extent marker to pointer fields in chapter 18.
SwayamInSync Oct 24, 2026
173faee
docs: List extents of pointer fields in the limitations.
SwayamInSync Oct 24, 2026
45590cf
docs: Note extents of pointer fields and the separation of empty exte…
SwayamInSync Oct 24, 2026
2e80378
docs: Describe extents of pointer fields in the design.
SwayamInSync Oct 24, 2026
16fdeb0
docs: Describe field parameters and the separation of extents in the …
SwayamInSync Oct 24, 2026
76aa3b9
verify: Mangle a constructor or destructor as its complete-object var…
SwayamInSync Oct 24, 2026
abcbf5d
Merge branch 'fix/per-function-errors' into fix/record-references.
SwayamInSync Oct 24, 2026
0cc2bd6
Merge branch 'fix/record-references' into fix/local-record-arguments.
SwayamInSync Oct 24, 2026
55407b1
Merge branch 'fix/local-record-arguments' into fix/pointer-field-exte…
SwayamInSync Oct 24, 2026
8f975cc
verify: Keep an in-class member function's clauses for its late-parse…
SwayamInSync Oct 24, 2026
2375cf7
verify: Cache the clauses of an in-class member function instead of i…
SwayamInSync Oct 24, 2026
900012b
verify: Parse a member function's clauses in the complete-class context.
SwayamInSync Oct 24, 2026
8b3e5c5
verify: Parse an out-of-line member's clauses in its class's scope, a…
SwayamInSync Oct 24, 2026
abbf009
verify: Remove the warning that contracts on member functions are ign…
SwayamInSync Oct 24, 2026
0b7a4bb
verify: Verify member functions as functions of this, and pass the ob…
SwayamInSync Oct 24, 2026
79bf37a
test: Check member functions and calls on objects.
SwayamInSync Oct 24, 2026
9f402e2
test: Check the parsing of member function clauses.
SwayamInSync Oct 24, 2026
c5f4aa3
test: Locate the error of a virtual function.
SwayamInSync Oct 24, 2026
fbe4e09
test: Expect the class template's warning on its member function.
SwayamInSync Oct 24, 2026
1e8572d
docs: Describe member functions, with a checked example.
SwayamInSync Oct 24, 2026
ffb7284
docs: Leave only templates unverified in the functions page.
SwayamInSync Oct 24, 2026
fc0b6a1
docs: List member functions as supported in the limitations.
SwayamInSync Oct 24, 2026
8771ab4
docs: Note member functions in the release notes.
SwayamInSync Oct 24, 2026
3d45aef
docs: Describe member functions in the design.
SwayamInSync Oct 24, 2026
5cebae0
docs: Describe member functions and the late parse of their clauses i…
SwayamInSync Oct 24, 2026
6e1b3f8
verify: Name a template or member function only when it has contracts…
SwayamInSync Oct 24, 2026
7412ac9
test: Check that a run under the Microsoft ABI mangles no template.
SwayamInSync Oct 24, 2026
0959fdd
Merge branch 'fix/per-function-errors' into fix/record-references.
SwayamInSync Oct 24, 2026
4b20a4d
Merge branch 'fix/record-references' into fix/local-record-arguments.
SwayamInSync Oct 24, 2026
6354f1f
Merge branch 'fix/local-record-arguments' into fix/pointer-field-exte…
SwayamInSync Oct 24, 2026
02015ad
Merge branch 'fix/pointer-field-extents' into fix/member-functions.
SwayamInSync Oct 24, 2026
3513ea8
verify: Assume an invariant's definedness at its loop's head, where a…
SwayamInSync Oct 24, 2026
962251b
test: Check loops that initialize local storage and invariants whose …
SwayamInSync Oct 24, 2026
cf024f0
verify: Assume at a loop's head only the definedness checks whose con…
SwayamInSync Oct 24, 2026
d0a17ce
docs: Describe an invariant's definedness at the head and initializat…
SwayamInSync Oct 24, 2026
fcd1d6c
docs: Note loops that initialize local storage in the release notes.
SwayamInSync Oct 24, 2026
b2e73ca
docs: State that an invariant holds with its definedness at the head …
SwayamInSync Oct 24, 2026
57b9e8e
docs: Describe definedness and initialization at a loop's head in the…
SwayamInSync Oct 24, 2026
d879449
verify: Frame a loop that writes local or dynamic storage by the cell…
SwayamInSync Oct 24, 2026
92f0ab7
test: Check that a loop writing local storage keeps every other object.
SwayamInSync Oct 24, 2026
a0698a7
docs: Describe the local and dynamic objects a loop writes, with a ch…
SwayamInSync Oct 24, 2026
6f9a7ca
docs: Note loops that write local storage in the release notes.
SwayamInSync Oct 24, 2026
7d5c123
docs: Count local and dynamic objects in a loop's write set in the de…
SwayamInSync Oct 24, 2026
991d0ef
docs: Describe loop frames of local and dynamic storage in the archit…
SwayamInSync Oct 24, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -1991,9 +1991,5 @@ def warn_contract_template_unsupported : Warning<
"contracts in %select{function|class}0 template %1 are not yet supported "
"and are ignored">,
InGroup<ContractUnsupported>;
def warn_contract_member_function_unsupported : Warning<
"contracts on member functions are not yet supported and are ignored; "
"move the function out of the class or verify it as a free function">,
InGroup<ContractUnsupported>;

} // end of Parser diagnostics
14 changes: 14 additions & 0 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -1311,6 +1311,12 @@ class Parser : public CodeCompletionHandler {
/// The set of tokens that make up an exception-specification that
/// has not yet been parsed.
CachedTokens *ExceptionSpecTokens;

/// CppVerify: the contract clauses of the declarator, parsed in the
/// complete-class context as a function contract specifier is.
std::unique_ptr<CachedTokens> ContractTokens;
bool ContractIsSpec = false;
bool ContractIsProof = false;
};

/// LateParsedMemberInitializer - An initializer for a non-static class data
Expand Down Expand Up @@ -7592,6 +7598,14 @@ class Parser : public CodeCompletionHandler {
bool isFunctionContractClause();
void ParseFunctionContractClauses(ParsingDeclarator &D,
FunctionContractClauses &Clauses);
/// The clauses at Tok, with the parameters and CurrentContractReturnType
/// already in place, and Clauses.Info.IsSpec and IsProof set.
void ParseFunctionContractClauseList(FunctionContractClauses &Clauses);
/// The clauses of an in-class member function declarator, cached for its
/// late-parsed declaration, where the class is complete.
std::unique_ptr<CachedTokens> MemberContractTokens;
bool MemberContractIsSpec = false;
bool MemberContractIsProof = false;
void attachFunctionContract(Decl *Function, FunctionContractClauses &Clauses);
/// A declaration ending in ';' after its clauses.
Decl *
Expand Down
41 changes: 41 additions & 0 deletions clang/lib/Parse/ParseCXXInlineMethods.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,47 @@ void Parser::ParseLexedMethodDeclaration(LateParsedMethodDeclaration &LM) {
LM.ExceptionSpecTokens = nullptr;
}

// CppVerify: the contract clauses, with the parameters in scope and `this`
// as in the exception-specification.
if (std::unique_ptr<CachedTokens> Toks = std::move(LM.ContractTokens)) {
ParenBraceBracketBalancer BalancerRAIIObj(*this);
Token ContractEnd;
ContractEnd.startToken();
ContractEnd.setKind(tok::eof);
ContractEnd.setLocation(Toks->back().getEndLoc());
ContractEnd.setEofData(LM.Method);
Toks->push_back(ContractEnd);
Toks->push_back(Tok);
PP.EnterTokenStream(*Toks, true, /*IsReinject*/ true);
ConsumeAnyToken(/*ConsumeCodeCompletionTok=*/true);

FunctionDecl *Function = LM.Method->getAsFunction();
auto *Method = dyn_cast_or_null<CXXMethodDecl>(Function);
ParseScope FnScope(this, Scope::FnScope);
Sema::ContextRAII FnContext(Actions, Function, /*NewThisContext=*/false);
Sema::CXXThisScopeRAII ThisScope(
Actions, Method ? Method->getParent() : nullptr,
Method ? Method->getMethodQualifiers() : Qualifiers{},
Method && !Method->isStatic());

FunctionContractClauses Contract;
Contract.Info.IsSpec = LM.ContractIsSpec;
Contract.Info.IsProof = LM.ContractIsProof;
PendingClauseProofs.clear();
CurrentContractReturnType =
Function ? Function->getReturnType() : Actions.getASTContext().IntTy;
ParseFunctionContractClauseList(Contract);
if (Tok.isNot(tok::eof) || Tok.getEofData() != LM.Method)
Diag(Tok.getLocation(), diag::err_expected) << tok::semi;
attachFunctionContract(LM.Method, Contract);
PendingClauseProofs.clear();

while (Tok.isNot(tok::eof))
ConsumeAnyToken();
if (Tok.is(tok::eof) && Tok.getEofData() == LM.Method)
ConsumeAnyToken();
}

InFunctionTemplateScope.Scopes.Exit();

// Finish the delayed C++ method declaration.
Expand Down
27 changes: 23 additions & 4 deletions clang/lib/Parse/ParseCppVerify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -358,12 +358,19 @@ void Parser::ParseFunctionContractClauses(ParsingDeclarator &D,
return;

// Re-enter function parameters into scope so contract conditions can
// reference them. This mirrors ParseTrailingRequiresClause in
// ParseDeclCXX.cpp: create a FunctionPrototypeScope and push params.
// reference them. This mirrors ParseTrailingRequiresClauseWithScope in
// ParseDeclCXX.cpp: an out-of-line member's clauses are in its class's
// scope, with `this`, and a FunctionPrototypeScope holds the parameters.
CXXScopeSpec &SS = D.getCXXScopeSpec();
DeclaratorScopeObj DeclScopeObj(*this, SS);
if (SS.isValid() && Actions.ShouldEnterDeclaratorScope(getCurScope(), SS))
DeclScopeObj.EnterDeclaratorScope();
ParseScope ContractParamScope(this, Scope::DeclScope |
Scope::FunctionDeclarationScope |
Scope::FunctionPrototypeScope);
Actions.ActOnStartTrailingRequiresClause(getCurScope(), D);
std::optional<Sema::CXXThisScopeRAII> ThisScope;
InitCXXThisScopeForDeclaratorIfRelevant(D, D.getDeclSpec(), ThisScope);

// Compute the return type from the full Declarator (not just the DeclSpec)
// so that result in postconditions gets the correct type: pointers,
Expand All @@ -376,7 +383,13 @@ void Parser::ParseFunctionContractClauses(ParsingDeclarator &D,
else
CurrentContractReturnType = Actions.getASTContext().IntTy;
}
ParseFunctionContractClauseList(Clauses);
}

void Parser::ParseFunctionContractClauseList(FunctionContractClauses &Clauses) {
FunctionContractInfo &I = Clauses.Info;
const bool IsSpecFn = I.IsSpec;
const bool IsProofFn = I.IsProof;
llvm::SaveAndRestore<unsigned> ContextRAII(CppVerifyContextDepth,
CppVerifyContextDepth + 1);
// ACSL behaviors: pre and post clauses after behavior(name, assumes)
Expand Down Expand Up @@ -663,8 +676,14 @@ void Parser::attachFunctionContract(Decl *Result,
// Templates are not verified yet: their clauses are ignored, as a member
// function's are.
if (FD->isTemplated() && !I.IsSpec && !I.IsProof) {
Diag(FD->getLocation(), diag::warn_contract_template_unsupported)
<< 0 << FD;
// A member of a class template is named by its class.
const auto *Method = dyn_cast<CXXMethodDecl>(FD);
if (Method && Method->getParent()->isTemplated())
Diag(FD->getLocation(), diag::warn_contract_template_unsupported)
<< 1 << Method->getParent();
else
Diag(FD->getLocation(), diag::warn_contract_template_unsupported)
<< 0 << FD;
return;
}
FunctionContractInfo &FCI = Ctx.getOrCreateFunctionContract(FD);
Expand Down
31 changes: 23 additions & 8 deletions clang/lib/Parse/ParseDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2364,6 +2364,10 @@ void Parser::HandleMemberFunctionDeclDelays(Declarator &DeclaratorInfo,
// If there was a late-parsed exception-specification, we'll need a
// late parse
bool NeedLateParse = FTI.getExceptionSpecType() == EST_Unparsed;
// So do contract clauses (CppVerify).
std::unique_ptr<CachedTokens> ContractTokens =
std::move(MemberContractTokens);
NeedLateParse = NeedLateParse || ContractTokens;

if (!NeedLateParse) {
// Look ahead to see if there are any default args
Expand Down Expand Up @@ -2396,6 +2400,9 @@ void Parser::HandleMemberFunctionDeclDelays(Declarator &DeclaratorInfo,
LateMethod->ExceptionSpecTokens = FTI.ExceptionSpecTokens;
FTI.ExceptionSpecTokens = nullptr;
}
LateMethod->ContractTokens = std::move(ContractTokens);
LateMethod->ContractIsSpec = MemberContractIsSpec;
LateMethod->ContractIsProof = MemberContractIsProof;
}
}

Expand Down Expand Up @@ -2980,19 +2987,27 @@ Parser::DeclGroupPtrTy Parser::ParseCXXClassMemberDeclaration(
return nullptr;
}

// CppVerify: contract clauses (pre/post/...) on in-class member functions are
// not yet modeled by the verifier, which handles free functions. Rather than
// emit a confusing "expected ';'", diagnose once and skip the clauses so the
// rest of the class still parses and the function is treated as uncontracted.
// CppVerify: the contract clauses of an in-class member function are parsed
// in the complete-class context, as a function contract specifier is (C++26
// [class.mem.general]), with the exception-specification and default
// arguments of its late-parsed declaration: their tokens are kept until
// then.
MemberContractTokens.reset();
if (getLangOpts().VerifyContracts && DeclaratorInfo.isFunctionDeclarator() &&
isFunctionContractClause()) {
Diag(Tok, diag::warn_contract_member_function_unsupported);
MemberContractTokens = std::make_unique<CachedTokens>();
MemberContractIsSpec =
DeclaratorInfo.getDeclSpec().isSpecFunctionSpecified();
MemberContractIsProof =
DeclaratorInfo.getDeclSpec().isProofFunctionSpecified();
while (isFunctionContractClause()) {
MemberContractTokens->push_back(Tok);
ConsumeCppVerify();
if (Tok.is(tok::l_paren)) {
BalancedDelimiterTracker T(*this, tok::l_paren);
if (!T.consumeOpen())
T.skipToEnd();
MemberContractTokens->push_back(Tok);
ConsumeParen();
ConsumeAndStoreUntil(tok::r_paren, *MemberContractTokens,
/*StopAtSemi=*/false, /*ConsumeFinalToken=*/true);
}
}
}
Expand Down
65 changes: 59 additions & 6 deletions clang/lib/Verify/Driver/Verifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3081,13 +3081,33 @@ class Verifier {
Converter.getUnverifiedCallers();
for (const auto &[Loc, Message] : Converter.getWarnings())
Diags.push_back({VerifyDiagnostic::Warning, Message, Loc});
// A construct the verifier does not represent costs its function alone:
// the function is Unresolved, its first error carrying the verdict, and
// the rest of the translation unit is verified. An error outside every
// function stops the run.
bool OutsideFunctions = false;
std::map<std::string, std::string> UnsupportedConstructs;
for (const ConversionError &Err : Converter.getErrors()) {
VerifyDiagnostic D{VerifyDiagnostic::Error, Err.Message,
Err.Range.getBegin()};
D.Span = Err.Range;
if (Err.Function.empty())
OutsideFunctions = true;
else
D.FunctionName = Err.FunctionName;
if (!Err.Function.empty() &&
UnsupportedConstructs.emplace(Err.Function, Err.Message).second) {
VerifyResult R;
R.Status = VerifyStatus::Unresolved;
R.Reason = VerifyReason::UnsupportedConstruct;
R.Message = Err.Message;
D.Result = std::move(R);
}
Diags.push_back(std::move(D));
}
if (!Converter.getErrors().empty())
if (OutsideFunctions)
return false;
if (Functions.empty() && !UnsupportedConstructs.empty())
return false;
if (Functions.empty()) {
if (Opts.LeanCertify) {
Expand Down Expand Up @@ -3213,7 +3233,7 @@ class Verifier {
};
const unsigned DumpLayers = Opts.DumpIRLayers;
const bool MultiLayerDump = llvm::popcount(DumpLayers) > 1;
bool AllOk = true;
bool AllOk = UnsupportedConstructs.empty();
bool AnyFailed = false;
std::set<std::string> FailedCallers;
// A spec whose termination is not established has no definition, so a
Expand Down Expand Up @@ -3562,12 +3582,35 @@ class Verifier {
// which is reported only if it fails.
if (Fn->Uninterpreted || (Fn->IsBuiltin && !Fn->NeedsDecreasesCheck))
continue;
// What a function says depends on the definitions of the specs it
// reaches, so one that reaches a spec the verifier does not
// represent is not verified.
std::string ReliesOn;
for (const std::string &Spec : Fn->SpecDependencies)
if (auto It = FnMap.find(Spec);
It != FnMap.end() && It->second->UnsupportedConstruct)
ReliesOn += (ReliesOn.empty() ? "" : ", ") + It->second->Name;
if (!ReliesOn.empty()) {
AllOk = false;
VerifyResult R;
R.Status = VerifyStatus::Unresolved;
R.Reason = VerifyReason::UnsupportedConstruct;
R.Message = "relies on " + ReliesOn +
", which uses a construct the verifier does not support";
VerifyDiagnostic D{VerifyDiagnostic::Unresolved,
Fn->Name + " [reason=construct.unsupported] (" +
R.Message + ")",
Fn->DeclLoc, Fn->Name};
D.Result = std::move(R);
Diags.push_back(std::move(D));
continue;
}
if (Fn->IsExternalContract) {
if (Fn->IsTrusted)
Diags.push_back({VerifyDiagnostic::Trusted,
Fn->Name + " (contract assumed, not verified)",
Fn->DeclLoc, Fn->Name});
else
else if (!Fn->UnsupportedConstruct)
Diags.push_back(
{VerifyDiagnostic::Warning,
Fn->Name + " has a contract but no definition, so its callers "
Expand Down Expand Up @@ -4925,6 +4968,8 @@ class Verifier {
auto Check = ContractChecks.find(Callee);
if (Check != ContractChecks.end() && !settled(Check->second))
Names += " (its clauses are not shown to be defined)";
else if (It != FnMap.end() && It->second->UnsupportedConstruct)
Names += " (it uses a construct the verifier does not support)";
else if (It != FnMap.end() && It->second->IsExternalContract &&
!It->second->IsTrusted)
Names += " (no definition; mark it [[cppverify::trusted]] to "
Expand Down Expand Up @@ -4959,9 +5004,12 @@ class Verifier {
continue;
// Definitions and frames of what the proof may reach;
// postconditions and unfoldings where its module assumes them.
std::string Undefined, Unframed, Unproven, Unruled;
std::string Unsupported, Undefined, Unframed, Unproven, Unruled;
for (const std::string &Identity : Reliance.Specs) {
if (UndefinedSpecs.count(Identity))
if (auto It = FnMap.find(Identity);
It != FnMap.end() && It->second->UnsupportedConstruct)
list(Unsupported, nameOf(Identity));
else if (UndefinedSpecs.count(Identity))
list(Undefined, nameOf(Identity));
else if (UnframedSpecs.count(Identity))
list(Unframed, nameOf(Identity));
Expand All @@ -4978,7 +5026,12 @@ class Verifier {
for (const std::string &Identity : Reliance.AssumedUnfoldings)
if (Unproved.count(Identity) && !Reliance.Withheld.count(Identity))
list(Unruled, nameOf(Identity));
if (!Undefined.empty())
if (!Unsupported.empty())
demote(Reliance.Index, VerifyReason::UnsupportedConstruct,
"relies on " + Unsupported +
", which uses a construct the verifier does not "
"support");
else if (!Undefined.empty())
demote(Reliance.Index, VerifyReason::SpecTermination,
"relies on the definition of " + Undefined +
", whose termination is not established");
Expand Down
Loading
Loading