Repository navigation
E11: predefine __cppverify__ for headers shared with other compilers, and locate failures in macro arguments where written - #119
Merged
Conversation
…ition of its own.
…ritten, as Clang does.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Plan item E11 (headers shared with other compilers): contracted code compiled only with this Clang and
-fverify-contracts, and nothing told a header which compiler read it.On the base
A header that GCC, MSVC, or upstream Clang also compiles could not keep its contracts:
cppverify::pre(...)after a declarator is a syntax error for them (expected function body after function declarator), and no macro distinguished this compiler with the flag from any other.__cppverify__was proposed in the syntax study (namespaced-syntax.md) and never defined.With this PR
With
-fverify-contracts, in C++, the compiler predefines:__cppverify__1__cppverify_major__,__cppverify_minor__,__cppverify_patchlevel__0,2,0for 0.2.0__cppverify_version__"0.2.0-dev", the stringcpp-verify --versionprintsA shared header wraps each construct in a macro that is empty without them:
The test's header (
Inputs/shared_header.h: a spec in an#ifdefblock, clauses, a loop's clauses, acppverify::check, and a ghost block, all wrapped) compiles without a warning under-Wall -Wextra -pedantic -Werrorwith GCC 13.3 and upstream Clang 18, in C++11 and C++20.Design
__cplusplus, not like__clang__. The macros say that the constructs are recognized here, a property of the language the file is compiled in, so they are defined with the standard macros, which-undefkeeps, and before the command line's, so-U__cppverify__removes them. They are not defined in C, where the constructs are not recognized, nor without the flag.clang/lib/Verify/CMakeLists.txttoclang/CMakeLists.txt, which splits it into its numbers and configures all of it intoclang/Basic/Version.incbeside Clang's own (CLANG_VERSION_MAJORand the rest), the headerInitPreprocessoralready reads for__clang_major__.--versionreads it from there too, so the macros and--versioncannot disagree; the website'sconf.pyandbuild-site.shread the new place.__FRAMAC__:share/libc/features.hdefines__PUSH_FC_STDLIBto a Frama-C pragma under it and to nothing otherwise. A variadic macro takes the commas of a clause, so one macro covers every construct written in a function; declarations only verification uses (specs, proof functions, a namespace alias) go in an#ifdefblock.Locations in macros
Guarded clauses are macro arguments, so where a location in a macro is shown matters now. The text error was already at the argument (Clang's renderer maps it), but the JSON record and the obligation's ID used
getPresumedLoc, which takes a macro location to the macro's use, and the counterexample's notes were mapped there on purpose:Every location the verifier prints now goes through
SourceManager::getFileLoc, Clang's rule: a token of a macro's argument where it is written, any other token of a macro where the macro is used. A range written in one place, such as one argument, is that place (Lexer::makeFileCharRange), and any other keeps the macro's use. A clause written in a macro's body (#define NONNEGATIVE cppverify::post(cppverify::result >= 0)) is still shown at the use, with Clang's "expanded from macro" note:The release moved, so
releaseVersion()(#105) readsCPPVERIFY_VERSION_STRINGtoo.Tests
predefined_macros.cpp(new): the macros with the flag, through%clang_cc1and the driver, and with-undef; none without the flag or in C;-U__cppverify__removes the first; and the version the macros spell is the onecpp-verify --versionprints (FileCheck captures the parts from the preprocessed file and matches them in--version's output).shared_header.cpp(new) withInputs/shared_header.h: cpp-verify verifies the guarded contracts (two proofs, a failure in a macro's argument, and one in a macro's body), with each location in the text and in JSON; the same file compiles without the flag as plain C++ under-Wall -Wextra -pedantic, and with-fverify-contracts -fno-verifyits IR has no trace of the spec.On the base both tests fail: no macro is defined, so the guarded contracts vanish and nothing is verified.
Mutants
Each mutant below, applied alone and rebuilt, is caught (10 of 10):
predefined_macros.cpp-undefpredefined_macros.cpp-Ucannot remove itpredefined_macros.cpppredefined_macros.cpp--version'spredefined_macros.cppshared_header.cppshared_header.cppshared_header.cppDocs
check-doc-examples.pypasses on every changed page (40 examples).