Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do you think it'd be possible to integrate the ASSERT() expressions with C++ contracts? #37

Open
GavinRay97 opened this issue Dec 10, 2022 · 2 comments
Labels
c++26 enhancement New feature or request

Comments

@GavinRay97
Copy link
Contributor

A few weeks ago, C++ Contracts support was merged into GCC:

One thing I keep thinking is how great it would be to be able to use libassert for the contract violation messages.

You are allowed to write your own assertion handler for failure, see below for an example with GCC Trunk and libassert v1.1:

Program returned: 139
contract violation: /app/example.cpp:30: num > 0 is false [with contract level=default]
violation occurs here:
./output.s[0x40356d]
./output.s[0x403728]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf3)[0x7f14fa9a4083]
./output.s[0x4032be]
[0x0]
end of violation
terminate called without an active exception

Could it be possible to somehow integrate libassert here, so that you get the much nicer debug message?
If you try to use DEBUG_ASSERT or ASSERT in the [[pre: ]] or post expression themselves, it fails:

<source>:30:12: error: statement-expressions are not allowed outside functions nor in template-argument lists
   30 |     [[pre: ASSERT(num > 0)]]

You have access to the original assertion expression text, ie num > 0, but I don't know that you have access to the value of IE num in the violation handler.

void handle_contract_violation(const std::experimental::contract_violation &violation) {
  size_t _backtraceSize{0};
  void *_backtrace[MAX_BACKTRACE_DEPTH]{};

  _backtraceSize = backtrace(_backtrace, MAX_BACKTRACE_DEPTH);
  if(_backtraceSize == MAX_BACKTRACE_DEPTH)
    std::cerr << "warning: backtrace may have been truncated" << std::endl;

  std::cerr << "contract violation: " << violation.file_name()
    << ":" << violation.line_number()
    << ": " << violation.comment() << " is false"
    << " [with contract level=" << violation.assertion_level() << "]" << std::endl
    << "violation occurs here:" << std::endl;
  // skip the stack frame of handle_contract_violation and
  // on_contract_violation to get to wherever the assert was
  backtrace_symbols_fd(_backtrace + 2, _backtraceSize - 1, STDERR_FILENO);
  std::cerr << "end of violation" << std::endl;
}

int square(int num)
    [[pre: num > 0]]
    [[post res: res < 100]]
{
    DEBUG_ASSERT(num * num < 50);
    return num * num;
}


int main()
{
    // Trigger PRE
    square(-1);
    // Trigger DEBUG_ASSERT
    // square(8);
    // Trigger POST
    // square(10);
    return 0;
}
@jeremy-rifkin
Copy link
Owner

Thanks for opening this issue! I'd definitely like to support contracts. [[pre: ASSERT(num > 0)]] would be required for getting the value of num and it should be possible to make this syntax work.

@jeremy-rifkin jeremy-rifkin added the enhancement New feature or request label Sep 13, 2024
@jeremy-rifkin
Copy link
Owner

Now that contracts have been merged into the C++26 draft and a lot of design iteration has taken place I'll re-evaluate this to see if it's possible.

[basic.contract.eval]/5 in the proposed wording reads

The evaluation A of a contract assertion using a checking semantic determines the value
of the predicate. It is unspecified whether the predicate is evaluated. Let B be the value
that would result from evaluating the predicate. [ Note: To determine whether a predicate
would evaluate to true or false, an alternative evaluation that produces the same value
as the predicate but has no side effects might be evaluated instead of the predicate,
resulting in the side effects of the predicate not occurring. [ Example:

struct S {
  mutable int g = 5;
} s;
void f()
  pre(( s.g++, false )); // #1
  void g()
{
  f(); // Increment of s.g may or may not occur, even if #1 uses a checking semantic
}

— end example ] — end note ]

This complicates things, so I'll have to study approaches more

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
c++26 enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants