Terminating the current macro

Hi experts,

how can I exit the current macro or the current command that I have typed in interactively? I want to enforce preconditions in a function and terminate execution if they are not fulfilled.

In compiled code I use assert so that the preconditions are only checked in debug build but not in release builds - and the whole program can exit if something is wrong. When running interactively, I always want to run checks. So I am trying to write my own myAssert macro. When an assertion fails, I want to stop macro execution but NOT exit root. For example, all TCanvas should stay open, just the current macro (or the command that I have typed in) should stop. How to do this?

Example:

// .L this function
double checked_sqrt(double d) {
  cout << "test1\n";
  if (d<0) STOP_MACRO_HERE;
  return sqrt(d);
}
// then typing
root[1] for (int i=0;i<2;++i) cout << checked_sqrt(-1) << '\n';
// should print "test1\n" ONCE
// then print "d<0 failed" and then greet mit with
root[2]

How do I define STOP_MACRO_HERE?
I have tried gApplication->Terminate(); but that quits ROOT as well.

Edit: ideally, I’d like to extend gsl::Expects(...), or in case [[expects condition]] becomes standard, it would be great if ROOT could support it with the described behavior (i.e. stop execution, not exiting ROOT).

It looks like you could throw an exception there.

yes, true (that is actually my current solution), but if someone is using exceptions, they might get caught somewhere in the code (maybe expecting only a certain kind of exception but simply catching using catch(std::exception&) -> thus I am currently throwing my own AssertException that does not inherit from std::exception. The only gotcha left is code like catch(...){ /* ignore */ }. This thing should be “more fatal” than an exception but less fatal than terminating root. However, the problem when not inheriting from std::exception is that the what() is not printed, you only get Error in <TRint::HandleTermInput()>: Exception caught! which isn’t useful. So maybe I should be throwing something like invalid_argument or logic_error. On the other hand I’d like to use it not only for preconditions in functions but add more checks everywhere in the code and I don’t want to interfere with existing exception handling.

I’d recommend to use exceptions but you could use the long jumps in TException.h. IIRC, we are using this to ‘recover’ from crashes.

The missing what call with a custom exception could be solved using some SFINAE detecting if the thrown object has a what method and call it. The issue with catch(...) is a tricky one, maybe we could solve it with using some global state but I’d not be in favor of this.

I am thinking of rewiring all llvm_unreachables to throw a new exception class of runtime exception. I am thinking of rewiring the asserts, too. I am not sure if that would help you, though.

Well, the current solution with exception throwing works. It is one more reason to catch only the specific exceptions and not ...!

The whole thing came up to me when using assert(false) in some code. In compiled code with debug, the program exits. In interactive ROOT, assert(false) does nothing. So if assert would do something useful in ROOT, that would indeed solve my problem.

Basically, I’d like to pass something like “g” to non-compiled root (mimic the root x.C+g below - root x.C+ and root x.C+g behave as expected).

$ cat x.C
#include <iostream>
void x() { assert(false); std::cout << "here\n"; }

$ root -l -q x.C

Processing x.C...
here
$ root -l -q x.C+g

Processing x.C+g...
Info in <TUnixSystem::ACLiC>: creating shared library x_C.so
root.exe: x.C:2: void x(): Assertion `false' failed.
$ touch x.C
$ root -l -q x.C+

Processing x.C+...
Info in <TUnixSystem::ACLiC>: creating shared library x_C.so
here

I am glad to hear that you have a working solution.

I think if we decide to rewire asserts into exceptions it would be something like if (!assert_cond) throw (assert_text); and you will more-or-less have a “g” behavior. If we decide against this and rewire only the llvm_unreachable write if (!assert_cond) llvm_unreachable and ROOT will rewire this for you. Alternatively, you could ‘easily’ implement an assert-to-exception transformation macro definition (there are a few resources on the internet that could be just pasted in).

PS: sorry for being punctual, but you shouldn’t use assert(false) but perhaps a wrapper over __builtin_unreachable().

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.