EvaluateWithSubstitution Usage

Hello fellow clang-ers,

I am looking to evaluate expressions with substitution, but I can’t seem to get clang::Expr’s EvaluateWithSubstitution to work correctly.

Let me set up this question. Consider the following code…

bool a = false;

if (a) {
std::cout << “HERE” << std::endl;
}

a = true;

Suppose that I am trying to remove code paths that cannot possibly be reached. So in this case I have a matcher that will pick out the condition of the if statement as a clang::Expr. I would like to determine whether or not this clang::Expr can be evaluated to true or false.

Suppose I am able to query the values of all of the variables that have deterministic values at the beginning of the condition. So my first approach was to construct a dummy function, where the arguments are named the same
and have the same types as these deterministic variables, for example

bool dummy_fn(bool a)

and then construct a vector of arguments, i.e. { false }, to apply to the function. Then I would use the condition’s EvaluateWithSubstitution method, passing in my dummy function and the corresponding arguments.

Unfortunately this approach does not seem to work, even with such a seemingly trivial example.

I have a feeling that the issue may be that the clang::DeclRefExpr of the ‘a’ within the condition’s clang::Expr is pointing to a clang::Decl that is not the same as the parameter of my dummy function, but I’m not sure of the best way to fix this (especially when the conditions become much more complicated and involving multiple clang::DeclRefExpr’s).

So my question is two-fold:
(1) Am I approaching this problem in the most “clang-y” way, or is there
some other approach I should be using that would work better?
(2) In your opinion is the issue with the above approach as I described,
i.e. that the clang::Decl of ‘a’ is not the same as the parameter 'a’s,
or is there something else that I may have missed?

Thank you very much for your help!
Anthony Burzillo <aburzillo@bloomberg.net>

Hello fellow clang-ers,

I am looking to evaluate expressions with substitution, but I can't seem to get clang::Expr's EvaluateWithSubstitution to work correctly.

Let me set up this question. Consider the following code...

bool a = false;

if (a) {
std::cout << "HERE" << std::endl;
}

a = true;

Suppose that I am trying to remove code paths that cannot possibly be reached. So in this case I have a matcher that will pick out the condition of the if statement as a clang::Expr. I would like to determine whether or not this clang::Expr can be evaluated to true or false.

Suppose I am able to query the values of all of the variables that have deterministic values at the beginning of the condition. So my first approach was to construct a dummy function, where the arguments are named the same
and have the same types as these deterministic variables, for example

bool dummy_fn(bool a)

and then construct a vector of arguments, i.e. { false }, to apply to the function. Then I would use the condition's EvaluateWithSubstitution method, passing in my dummy function and the corresponding arguments.

Unfortunately this approach does not seem to work, even with such a seemingly trivial example.

I have a feeling that the issue may be that the clang::DeclRefExpr of the 'a' within the condition's clang::Expr is pointing to a clang::Decl that is not the same as the parameter of my dummy function, but I'm not sure of the best way to fix this (especially when the conditions become much more complicated and involving multiple clang::DeclRefExpr's).

Yes, that's the problem. EvaluateWithSubstitution sets up a context
where the parameters of the specified FunctionDecl have the specified
expressions as their initializers. We don't provide a more general
interface to allow you to specify the values of local variables within
that function, but that would seem like a natural and useful
extension.

So my question is two-fold:
(1) Am I approaching this problem in the most "clang-y" way, or is there
some other approach I should be using that would work better?

Implementing this check on top of the static analyzer might be a
better choice; you'd get a substantially more powerful inference
engine for determining what code is unreachable that way (for
instance, it will consider how the values of local variables evolve
over the course of the function, not merely their initial values).

(2) In your opinion is the issue with the above approach as I described,
i.e. that the clang::Decl of 'a' is not the same as the parameter 'a's,
or is there something else that I may have missed?

Yes, that will be the problem.

Hello fellow clang-ers,

I am looking to evaluate expressions with substitution, but I can't seem to get clang::Expr's EvaluateWithSubstitution to work correctly.

Let me set up this question. Consider the following code...

bool a = false;

if (a) {
std::cout << "HERE" << std::endl;
}

a = true;

Suppose that I am trying to remove code paths that cannot possibly be reached. So in this case I have a matcher that will pick out the condition of the if statement as a clang::Expr. I would like to determine whether or not this clang::Expr can be evaluated to true or false.

Suppose I am able to query the values of all of the variables that have deterministic values at the beginning of the condition. So my first approach was to construct a dummy function, where the arguments are named the same
and have the same types as these deterministic variables, for example

bool dummy_fn(bool a)

and then construct a vector of arguments, i.e. { false }, to apply to the function. Then I would use the condition's EvaluateWithSubstitution method, passing in my dummy function and the corresponding arguments.

Unfortunately this approach does not seem to work, even with such a seemingly trivial example.

I have a feeling that the issue may be that the clang::DeclRefExpr of the 'a' within the condition's clang::Expr is pointing to a clang::Decl that is not the same as the parameter of my dummy function, but I'm not sure of the best way to fix this (especially when the conditions become much more complicated and involving multiple clang::DeclRefExpr's).

Yes, that's the problem. EvaluateWithSubstitution sets up a context
where the parameters of the specified FunctionDecl have the specified
expressions as their initializers. We don't provide a more general
interface to allow you to specify the values of local variables within
that function, but that would seem like a natural and useful
extension.

So my question is two-fold:
(1) Am I approaching this problem in the most "clang-y" way, or is there
some other approach I should be using that would work better?

Implementing this check on top of the static analyzer might be a
better choice; you'd get a substantially more powerful inference
engine for determining what code is unreachable that way (for
instance, it will consider how the values of local variables evolve
over the course of the function, not merely their initial values).

Depends. The static analyzer is good in making sure that execution paths it finds do actually make sense, and it tries to find as many of them as possible, but it's pretty bad at making sure it finds all of them. If your purpose is to cut off the if-statement entirely (because the condition is always false) and you want to avoid cutting off a statement that is in fact reachable, the analyzer isn't the right tool; a more ad-hoc data flow analysis over the Clang CFG might be better. The analyzer is only good for the opposite kind of problems: "find an execution path through the program such that...".