Getting DecompositionDecl from BindingDecl

classic Classic list List threaded Threaded
14 messages Options
Reply | Threaded
Open this post in threaded view
|

Getting DecompositionDecl from BindingDecl

Manuel Klimek via cfe-dev
Hi,

I am trying to support c++17 structured bindings in the static analyzer, and I was really surprised to learn there is no reasonable way to find a
DecompositionDecl from a BindingDecl (that is often necessary because DecompositionDecl often is the only available VarDecl).
Shouldn’t getParentContext() be usable here?
Any clues for how this can be solved apart from preprocessing and populating parent pointers?

George
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Getting DecompositionDecl from BindingDecl

Manuel Klimek via cfe-dev
On 28 March 2018 at 17:27, George Karpenkov via cfe-dev <[hidden email]> wrote:
Hi,

I am trying to support c++17 structured bindings in the static analyzer, and I was really surprised to learn there is no reasonable way to find a
DecompositionDecl from a BindingDecl (that is often necessary because DecompositionDecl often is the only available VarDecl).
Shouldn’t getParentContext() be usable here?
Any clues for how this can be solved apart from preprocessing and populating parent pointers?

getParentContext() doesn't seem appropriate to me, because a DecompositionDecl is not really a DeclContext in any normal sense -- it doesn't "contain" other declarations, in the same way that in "struct X {} x;", the declaration of "x" does not "contain" the declaration of "struct X". Rather, we have a syntactic construct that happens to declare multiple related things at once. Can you say more about why the static analyzer might want to map from a BindingDecl to a DecompositionDecl? BindingDecls should generally just be treated wrappers around some lvalue expression.

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Getting DecompositionDecl from BindingDecl

Manuel Klimek via cfe-dev
Hi Richard,

Thanks for your reply!

> Can you say more about why the static analyzer might want to map from a BindingDecl to a DecompositionDecl?

One thing I couldn’t figure out is how to figure out whether a given binding represents a global.
But turns out that for my use case turns out that somehow was not required.

> BindingDecls should generally just be treated wrappers around some lvalue expression.

Right, yes, that unfortunately forces quite a lot of special-casing on us, as suddenly in many places where we expected only a VarDecl we know get a BindingDecl.

Regards,
George
_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Getting DecompositionDecl from BindingDecl

Manuel Klimek via cfe-dev
On 29 March 2018 at 15:08, George Karpenkov via cfe-dev <[hidden email]> wrote:
Hi Richard,

Thanks for your reply!

> Can you say more about why the static analyzer might want to map from a BindingDecl to a DecompositionDecl?

One thing I couldn’t figure out is how to figure out whether a given binding represents a global.
But turns out that for my use case turns out that somehow was not required.

I'm still not sure why you'd want to know that.

> BindingDecls should generally just be treated wrappers around some lvalue expression.

Right, yes, that unfortunately forces quite a lot of special-casing on us, as suddenly in many places where we expected only a VarDecl we know get a BindingDecl.

What kind of places? The intended operational semantics are that when you see a DeclRefExpr naming a BindingDecl, you evaluate its associated subexpression. I'd imagine this is best modeled by generating CFG nodes for the subexpression on each occurrence of such a DeclRefExpr, much like (IIRC) is done for CXXDefaultArgExpr and CXXDefaultInitExpr. That seems like it would not require too many special cases elsewhere.

(Perhaps the static analyzer needs more than that in order to produce more user-friendly diagnostics?)

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Getting DecompositionDecl from BindingDecl

Manuel Klimek via cfe-dev


On Mar 29, 2018, at 4:37 PM, Richard Smith <[hidden email]> wrote:

On 29 March 2018 at 15:08, George Karpenkov via cfe-dev <[hidden email]> wrote:
Hi Richard,

Thanks for your reply!

> Can you say more about why the static analyzer might want to map from a BindingDecl to a DecompositionDecl?

One thing I couldn’t figure out is how to figure out whether a given binding represents a global.
But turns out that for my use case turns out that somehow was not required.

I'm still not sure why you'd want to know that.

Turns out I don’t actually need this for my specific use case.
But in general the analyzer often has different behavior for globals, as analysis runs on a single translation unit,
and has to assume that any other translation unit can do whatever it wants to the globals.


> BindingDecls should generally just be treated wrappers around some lvalue expression.

Right, yes, that unfortunately forces quite a lot of special-casing on us, as suddenly in many places where we expected only a VarDecl we know get a BindingDecl.

What kind of places?

Quite a few of them.
E.g. in https://reviews.llvm.org/D44956 liveness analysis had to be re-done for binding declarations (if all BindingDecls had an underlying VarDecl the code change would have been around four lines instead).
The memory handling has to be extended to introduce a special class for dealing with binding declarations
(again, would have been avoided if they had an underlying VarDecl) [e.g. partial fix just to avoid the crash is in https://reviews.llvm.org/D44183]

In my understanding, clang itself has the same problem with strange special cases like not being able to capture a binding in a lambda.

The intended operational semantics are that when you see a DeclRefExpr naming a BindingDecl, you evaluate its associated subexpression.

Right, but what we also need to do is to figure out what to do with a BindingDecl when we see it on its own.
Also to evaluate all its subexpressions we need to introduce special casing for BindingDecl’s, as they are not VarDecl’s anymore.

I'd imagine this is best modeled by generating CFG nodes for the subexpression on each occurrence of such a DeclRefExpr, much like (IIRC) is done for CXXDefaultArgExpr and CXXDefaultInitExpr. That seems like it would not require too many special cases elsewhere.

(Perhaps the static analyzer needs more than that in order to produce more user-friendly diagnostics?)

We are not even there yet for structured bindings, just trying to make the analyzer understand them.




_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Getting DecompositionDecl from BindingDecl

Manuel Klimek via cfe-dev
On 30 March 2018 at 11:01, George Karpenkov via cfe-dev <[hidden email]> wrote:
On Mar 29, 2018, at 4:37 PM, Richard Smith <[hidden email]> wrote:

On 29 March 2018 at 15:08, George Karpenkov via cfe-dev <[hidden email]> wrote:
Hi Richard,

Thanks for your reply!

> Can you say more about why the static analyzer might want to map from a BindingDecl to a DecompositionDecl?

One thing I couldn’t figure out is how to figure out whether a given binding represents a global.
But turns out that for my use case turns out that somehow was not required.

I'm still not sure why you'd want to know that.

Turns out I don’t actually need this for my specific use case.
But in general the analyzer often has different behavior for globals, as analysis runs on a single translation unit,
and has to assume that any other translation unit can do whatever it wants to the globals.

OK, but a BindingDecl isn't a global (it's not even an object, just a symbolic name for an expression). It might represent an lvalue expression that denotes a global, but that global will be either a DecompositionDecl or an implicitly-introduced holding variable, both of which you can readily identify as being globals.
> BindingDecls should generally just be treated wrappers around some lvalue expression.

Right, yes, that unfortunately forces quite a lot of special-casing on us, as suddenly in many places where we expected only a VarDecl we know get a BindingDecl.

What kind of places?

Quite a few of them.
E.g. in https://reviews.llvm.org/D44956 liveness analysis had to be re-done for binding declarations (if all BindingDecls had an underlying VarDecl the code change would have been around four lines instead).
The memory handling has to be extended to introduce a special class for dealing with binding declarations
(again, would have been avoided if they had an underlying VarDecl) [e.g. partial fix just to avoid the crash is in https://reviews.llvm.org/D44183]

It seems to me that the problem here is actually that the CFG is mismodeling BindingDecls. If it expanded them to their expression, I don't think you'd need any special handling here.
 
In my understanding, clang itself has the same problem with strange special cases like not being able to capture a binding in a lambda.

You can't capture a binding in a lambda because a binding is not a variable, per the C++ standard's rules. This is not a clang problem.
The intended operational semantics are that when you see a DeclRefExpr naming a BindingDecl, you evaluate its associated subexpression.

Right, but what we also need to do is to figure out what to do with a BindingDecl when we see it on its own.
Also to evaluate all its subexpressions we need to introduce special casing for BindingDecl’s, as they are not VarDecl’s anymore.

I think you may be misunderstanding the semantic model we're using here. BindingDecls have nothing to do with VarDecls; they're a completely different kind of thing with completely different semantics, just like EnumConstantDecls are a completely different kind of thing with completely different evaluation semantics.

Simple example:

struct A { int x, y; };

void f(A a) {
  auto [v, w] = a;
  use(v, w);
}

This gives you a DecompositionDecl, which is a kind of VarDecl, of type A, initialized with 'a'. Let's call that 'e'.
It also gives you two BindingDecls, which are symbolic names for the expressions 'e.x' and 'e.y'.
So the evaluation semantics of the above function are as if you wrote:

void f(A a) {
  A e = a;
  use(e.x, e.y);
}

That's what the CFG for the above function should represent. The BindingDecls should not even show up, except as sugar so that clients who care can know that the 'e.x' expression was /written as/ 'v'.
I'd imagine this is best modeled by generating CFG nodes for the subexpression on each occurrence of such a DeclRefExpr, much like (IIRC) is done for CXXDefaultArgExpr and CXXDefaultInitExpr. That seems like it would not require too many special cases elsewhere.

(Perhaps the static analyzer needs more than that in order to produce more user-friendly diagnostics?)

We are not even there yet for structured bindings, just trying to make the analyzer understand them.




_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev



_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Getting DecompositionDecl from BindingDecl

Manuel Klimek via cfe-dev
Hi Richard,

Thanks for your reply!

OK, but a BindingDecl isn't a global (it's not even an object, just a symbolic name for an expression). It might represent an lvalue expression that denotes a global, but that global will be either a DecompositionDecl or an implicitly-introduced holding variable, both of which you can readily identify as being globals.

Right, sure, but I don’t have a convenient way to find that DecompositionDecl from a given BindingDecl,
and sometimes I need to act based on the BindingDecl alone.

It seems to me that the problem here is actually that the CFG is mismodeling BindingDecls. If it expanded them to their expression, I don't think you'd need any special handling here.

Could you clarify what you mean? For the analyzer, the CFG is just used to model the control flow, and to separate it into statements.
Given a statement, the analyzer processes it just based on AST.
What would “expand” mean here? Defining a kind of intermediate representation the analyzer operates on?
 
In my understanding, clang itself has the same problem with strange special cases like not being able to capture a binding in a lambda.

You can't capture a binding in a lambda because a binding is not a variable, per the C++ standard's rules. This is not a clang problem.
The intended operational semantics are that when you see a DeclRefExpr naming a BindingDecl, you evaluate its associated subexpression.

Right, but what we also need to do is to figure out what to do with a BindingDecl when we see it on its own.
Also to evaluate all its subexpressions we need to introduce special casing for BindingDecl’s, as they are not VarDecl’s anymore.

I think you may be misunderstanding the semantic model we're using here. BindingDecls have nothing to do with VarDecls; they're a completely different kind of thing with completely different semantics, just like EnumConstantDecls are a completely different kind of thing with completely different evaluation semantics.

Yes, yes, of course I understand that Clang implements the standard correctly.
I was just saying that the wording of c++17 standard is a bit unfortunate for us,
since it means a lot of special casing.


Simple example:

struct A { int x, y; };

void f(A a) {
  auto [v, w] = a;
  use(v, w);
}

This gives you a DecompositionDecl, which is a kind of VarDecl, of type A, initialized with 'a'. Let's call that 'e'.
It also gives you two BindingDecls, which are symbolic names for the expressions 'e.x' and 'e.y'.
So the evaluation semantics of the above function are as if you wrote:

void f(A a) {
  A e = a;
  use(e.x, e.y);
}

Right, thanks for the clarification!
In my mind, the final version was equivalent to

void f(A a) {
  auto &v = a.x;
  auto &w = a.y;
  use(v, w);
}

but I guess that’s not the case.
Was a different model chosen in the standard due to performance considerations?


That's what the CFG for the above function should represent.

Sorry, I’m not sure what do you mean here: from my understanding, CFG does not transform AST inside statements (apart from maybe tiny syntactic things).

The BindingDecls should not even show up, except as sugar so that clients who care can know that the 'e.x' expression was /written as/ 'v'.
I'd imagine this is best modeled by generating CFG nodes for the subexpression on each occurrence of such a DeclRefExpr, much like (IIRC) is done for CXXDefaultArgExpr and CXXDefaultInitExpr. That seems like it would not require too many special cases elsewhere.

(Perhaps the static analyzer needs more than that in order to produce more user-friendly diagnostics?)

We are not even there yet for structured bindings, just trying to make the analyzer understand them.




_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Getting DecompositionDecl from BindingDecl

Manuel Klimek via cfe-dev
On Fri, 30 Mar 2018, 20:22 George Karpenkov via cfe-dev, <[hidden email]> wrote:
Hi Richard,

Thanks for your reply!

OK, but a BindingDecl isn't a global (it's not even an object, just a symbolic name for an expression). It might represent an lvalue expression that denotes a global, but that global will be either a DecompositionDecl or an implicitly-introduced holding variable, both of which you can readily identify as being globals.

Right, sure, but I don’t have a convenient way to find that DecompositionDecl from a given BindingDecl,
and sometimes I need to act based on the BindingDecl alone.

Can you give an example?
It seems to me that the problem here is actually that the CFG is mismodeling BindingDecls. If it expanded them to their expression, I don't think you'd need any special handling here.

Could you clarify what you mean? For the analyzer, the CFG is just used to model the control flow, and to separate it into statements.
Given a statement, the analyzer processes it just based on AST.
What would “expand” mean here? Defining a kind of intermediate representation the analyzer operates on?

Yes, see below.
 
In my understanding, clang itself has the same problem with strange special cases like not being able to capture a binding in a lambda.

You can't capture a binding in a lambda because a binding is not a variable, per the C++ standard's rules. This is not a clang problem.
The intended operational semantics are that when you see a DeclRefExpr naming a BindingDecl, you evaluate its associated subexpression.

Right, but what we also need to do is to figure out what to do with a BindingDecl when we see it on its own.
Also to evaluate all its subexpressions we need to introduce special casing for BindingDecl’s, as they are not VarDecl’s anymore.

I think you may be misunderstanding the semantic model we're using here. BindingDecls have nothing to do with VarDecls; they're a completely different kind of thing with completely different semantics, just like EnumConstantDecls are a completely different kind of thing with completely different evaluation semantics.

Yes, yes, of course I understand that Clang implements the standard correctly.
I was just saying that the wording of c++17 standard is a bit unfortunate for us,
since it means a lot of special casing.


Simple example:

struct A { int x, y; };

void f(A a) {
  auto [v, w] = a;
  use(v, w);
}

This gives you a DecompositionDecl, which is a kind of VarDecl, of type A, initialized with 'a'. Let's call that 'e'.
It also gives you two BindingDecls, which are symbolic names for the expressions 'e.x' and 'e.y'.
So the evaluation semantics of the above function are as if you wrote:

void f(A a) {
  A e = a;
  use(e.x, e.y);
}

Right, thanks for the clarification!
In my mind, the final version was equivalent to

void f(A a) {
  auto &v = a.x;
  auto &w = a.y;
  use(v, w);
}

but I guess that’s not the case.
Was a different model chosen in the standard due to performance considerations?

It was chosen because it matches the semantic model desired by the designers of the feature. For example, you can't handle bitfields if you model structured bindings as reference variables.

This was a somewhat controversial decision, but it doesn't look like it's going to be reversed.
That's what the CFG for the above function should represent.

Sorry, I’m not sure what do you mean here: from my understanding, CFG does not transform AST inside statements (apart from maybe tiny syntactic things).

IIRC, the CFG expands CXXDefaultArgExprs and CXXDefaultInitExprs; this case is analogous to those.
The BindingDecls should not even show up, except as sugar so that clients who care can know that the 'e.x' expression was /written as/ 'v'.
I'd imagine this is best modeled by generating CFG nodes for the subexpression on each occurrence of such a DeclRefExpr, much like (IIRC) is done for CXXDefaultArgExpr and CXXDefaultInitExpr. That seems like it would not require too many special cases elsewhere.

(Perhaps the static analyzer needs more than that in order to produce more user-friendly diagnostics?)

We are not even there yet for structured bindings, just trying to make the analyzer understand them.




_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Getting DecompositionDecl from BindingDecl

Manuel Klimek via cfe-dev
Hi Richard,

Thanks for your reply!

On Mar 30, 2018, at 8:49 PM, Richard Smith <[hidden email]> wrote:



Right, sure, but I don’t have a convenient way to find that DecompositionDecl from a given BindingDecl,
and sometimes I need to act based on the BindingDecl alone.

Can you give an example?

Let’s say a structured binding is written into, and then some function is called, and then we read from that binding again.
If it was global, we have to assume any function call can invalidate it, but if it’s local and it wasn’t passed as a parameter,
chances are it will remain the same.

It was chosen because it matches the semantic model desired by the designers of the feature. For example, you can't handle bitfields if you model structured bindings as reference variables.

This was a somewhat controversial decision, but it doesn't look like it's going to be reversed.
That's what the CFG for the above function should represent.

Sorry, I’m not sure what do you mean here: from my understanding, CFG does not transform AST inside statements (apart from maybe tiny syntactic things).

IIRC, the CFG expands CXXDefaultArgExprs and CXXDefaultInitExprs; this case is analogous to those.

Yes, you are right; To be honest, I wasn’t previously familiar with that part of the codebase.
Yet still, those are very simple replacements, and IIRC those are the only two.

Supporting structured bindings would be indeed easier if we could have a simpler AST,
could you give an advice on what would be an equivalent AST we should rewrite to?

Would producing a MemberExpr reading from the struct at *use* time be completely semantically equivalent?
My previous impression was that for structured bindings load from the struct happens when the binding occurs,
not when the actual read is performed.
[though of course such rewrites would impede producing good diagnostic messages for the user]

The BindingDecls should not even show up, except as sugar so that clients who care can know that the 'e.x' expression was /written as/ 'v'.
I'd imagine this is best modeled by generating CFG nodes for the subexpression on each occurrence of such a DeclRefExpr, much like (IIRC) is done for CXXDefaultArgExpr and CXXDefaultInitExpr. That seems like it would not require too many special cases elsewhere.

(Perhaps the static analyzer needs more than that in order to produce more user-friendly diagnostics?)

We are not even there yet for structured bindings, just trying to make the analyzer understand them.




_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Getting DecompositionDecl from BindingDecl

Manuel Klimek via cfe-dev
On 2 April 2018 at 13:52, George Karpenkov via cfe-dev <[hidden email]> wrote:
Hi Richard,

Thanks for your reply!

On Mar 30, 2018, at 8:49 PM, Richard Smith <[hidden email]> wrote:



Right, sure, but I don’t have a convenient way to find that DecompositionDecl from a given BindingDecl,
and sometimes I need to act based on the BindingDecl alone.

Can you give an example?

Let’s say a structured binding is written into, and then some function is called, and then we read from that binding again.
If it was global, we have to assume any function call can invalidate it, but if it’s local and it wasn’t passed as a parameter,
chances are it will remain the same.

I think that will just work if you expand references to BindingDecls into their binding expressions: both before and after, you'll end up evaluating an lvalue denoting the same subobject of the DecompositionDecl.
It was chosen because it matches the semantic model desired by the designers of the feature. For example, you can't handle bitfields if you model structured bindings as reference variables.

This was a somewhat controversial decision, but it doesn't look like it's going to be reversed.
That's what the CFG for the above function should represent.

Sorry, I’m not sure what do you mean here: from my understanding, CFG does not transform AST inside statements (apart from maybe tiny syntactic things).

IIRC, the CFG expands CXXDefaultArgExprs and CXXDefaultInitExprs; this case is analogous to those.

Yes, you are right; To be honest, I wasn’t previously familiar with that part of the codebase.
Yet still, those are very simple replacements, and IIRC those are the only two.

Supporting structured bindings would be indeed easier if we could have a simpler AST,
could you give an advice on what would be an equivalent AST we should rewrite to?

You should rewrite a DeclRefExpr denoting a BindingDecl into the binding expression (BindingDecl::getBinding()) of that binding.
 
Would producing a MemberExpr reading from the struct at *use* time be completely semantically equivalent?

Yes.
 
My previous impression was that for structured bindings load from the struct happens when the binding occurs,
not when the actual read is performed.
[though of course such rewrites would impede producing good diagnostic messages for the user]

The member access happens each time the binding is named, not up-front.

(However, for a tuple-like class type -- eg, std::tuple<...> or std::pair<...> -- the binding declarations have expressions that denote auxiliary variables (BindingDecl::getHoldingVar()) which are initialized up-front. In order to correctly handle those cases, when you build the CFG for a DecompositionDecl, you'll need to walk its bindings, check for holding variables, and also build CFG for those variables. You can search for "getHoldingVar()" through the clang codebase to see the other places this is already done -- in CodeGen and the constant expression evaluator.)
 
The BindingDecls should not even show up, except as sugar so that clients who care can know that the 'e.x' expression was /written as/ 'v'.
I'd imagine this is best modeled by generating CFG nodes for the subexpression on each occurrence of such a DeclRefExpr, much like (IIRC) is done for CXXDefaultArgExpr and CXXDefaultInitExpr. That seems like it would not require too many special cases elsewhere.

(Perhaps the static analyzer needs more than that in order to produce more user-friendly diagnostics?)

We are not even there yet for structured bindings, just trying to make the analyzer understand them.




_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev



_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Getting DecompositionDecl from BindingDecl

Manuel Klimek via cfe-dev
Hi Richard,

Thanks for your reply.
Rewriting the AST does sound like a reasonable proposition indeed!
We’ll see whether it can be done without compromising user-friendly diagnostics.

George

On Apr 2, 2018, at 2:11 PM, Richard Smith <[hidden email]> wrote:

On 2 April 2018 at 13:52, George Karpenkov via cfe-dev <[hidden email]> wrote:
Hi Richard,

Thanks for your reply!

On Mar 30, 2018, at 8:49 PM, Richard Smith <[hidden email]> wrote:



Right, sure, but I don’t have a convenient way to find that DecompositionDecl from a given BindingDecl,
and sometimes I need to act based on the BindingDecl alone.

Can you give an example?

Let’s say a structured binding is written into, and then some function is called, and then we read from that binding again.
If it was global, we have to assume any function call can invalidate it, but if it’s local and it wasn’t passed as a parameter,
chances are it will remain the same.

I think that will just work if you expand references to BindingDecls into their binding expressions: both before and after, you'll end up evaluating an lvalue denoting the same subobject of the DecompositionDecl.
It was chosen because it matches the semantic model desired by the designers of the feature. For example, you can't handle bitfields if you model structured bindings as reference variables.

This was a somewhat controversial decision, but it doesn't look like it's going to be reversed.
That's what the CFG for the above function should represent.

Sorry, I’m not sure what do you mean here: from my understanding, CFG does not transform AST inside statements (apart from maybe tiny syntactic things).

IIRC, the CFG expands CXXDefaultArgExprs and CXXDefaultInitExprs; this case is analogous to those.

Yes, you are right; To be honest, I wasn’t previously familiar with that part of the codebase.
Yet still, those are very simple replacements, and IIRC those are the only two.

Supporting structured bindings would be indeed easier if we could have a simpler AST,
could you give an advice on what would be an equivalent AST we should rewrite to?

You should rewrite a DeclRefExpr denoting a BindingDecl into the binding expression (BindingDecl::getBinding()) of that binding.
 
Would producing a MemberExpr reading from the struct at *use* time be completely semantically equivalent?

Yes.
 
My previous impression was that for structured bindings load from the struct happens when the binding occurs,
not when the actual read is performed.
[though of course such rewrites would impede producing good diagnostic messages for the user]

The member access happens each time the binding is named, not up-front.

(However, for a tuple-like class type -- eg, std::tuple<...> or std::pair<...> -- the binding declarations have expressions that denote auxiliary variables (BindingDecl::getHoldingVar()) which are initialized up-front. In order to correctly handle those cases, when you build the CFG for a DecompositionDecl, you'll need to walk its bindings, check for holding variables, and also build CFG for those variables. You can search for "getHoldingVar()" through the clang codebase to see the other places this is already done -- in CodeGen and the constant expression evaluator.)
 
The BindingDecls should not even show up, except as sugar so that clients who care can know that the 'e.x' expression was /written as/ 'v'.
I'd imagine this is best modeled by generating CFG nodes for the subexpression on each occurrence of such a DeclRefExpr, much like (IIRC) is done for CXXDefaultArgExpr and CXXDefaultInitExpr. That seems like it would not require too many special cases elsewhere.

(Perhaps the static analyzer needs more than that in order to produce more user-friendly diagnostics?)

We are not even there yet for structured bindings, just trying to make the analyzer understand them.




_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Getting DecompositionDecl from BindingDecl

Manuel Klimek via cfe-dev
In reply to this post by Manuel Klimek via cfe-dev


On 4/2/18 2:11 PM, Richard Smith via cfe-dev wrote:
On 2 April 2018 at 13:52, George Karpenkov via cfe-dev <[hidden email]> wrote:
Hi Richard,

Thanks for your reply!

On Mar 30, 2018, at 8:49 PM, Richard Smith <[hidden email]> wrote:



Right, sure, but I don’t have a convenient way to find that DecompositionDecl from a given BindingDecl,
and sometimes I need to act based on the BindingDecl alone.

Can you give an example?

Let’s say a structured binding is written into, and then some function is called, and then we read from that binding again.
If it was global, we have to assume any function call can invalidate it, but if it’s local and it wasn’t passed as a parameter,
chances are it will remain the same.

I think that will just work if you expand references to BindingDecls into their binding expressions: both before and after, you'll end up evaluating an lvalue denoting the same subobject of the DecompositionDecl.
It was chosen because it matches the semantic model desired by the designers of the feature. For example, you can't handle bitfields if you model structured bindings as reference variables.

This was a somewhat controversial decision, but it doesn't look like it's going to be reversed.
That's what the CFG for the above function should represent.

Sorry, I’m not sure what do you mean here: from my understanding, CFG does not transform AST inside statements (apart from maybe tiny syntactic things).

IIRC, the CFG expands CXXDefaultArgExprs and CXXDefaultInitExprs; this case is analogous to those.

Thank you for the explanation! I was also very confused.

We do expand CXXDefaultInitExprs for sema warnings CFG, but not for the CFG analyzer. We don't expand CXXDefaultArgExprs yet.

I have a concern, which is probably invalid, about expanding expressions that can appear more than once. So far in a lot of places (in the analyzer in particular) we've been relying on every expression appearing only once within a single CFG, which would no longer be the case if we expand CXXDefaultArgExprs or DeclRefExprs-to-BindingDecls.

In particular, in the analyzer it's common to keep track of "the value of the expression". We are unable to handle the situation when the same expression, within the same call stack frame, in the same moment of time, has two different values. For BindingDecl this shouldn't be a problem because its expression will always have the same value. For CXXDefaultArgExpr it seems to also not be a problem because it is always surrounded by its respective function call, which is already the next moment of time - and we won't expand the same CXXDefaultArgExpr twice in the same call. Even if CXXDefaultArgExpr calls itself recursively, we're not on the same stack frame anymore. Am i understanding correctly that we're not ever going to be required to maintain two different values for CXXDefaultArgExpr sub-expressions or for binding sub expressions? Is there something that protects us from such situations, apart from "that's where we are at the moment"?

The other problem i'm immediately seeing in the analyzer is to prevent it from thinking that we've found an infinite loop when we visit the same expression twice without any change in the state of the program (which is a known but presumably relatively harmless bug in our current CXXDefaultArgExpr handling). But that should be relatively easy to resolve.

There is also a certain amount of "unknown unknowns" here, because i've no idea in how many other places we rely upon, or will need to rely upon every expression appearing only once.

The alternative i've been considering for now was to provide "fake stack frames" for evaluating such expandable expressions instead of expanding them directly into the CFG. This would be an analyzer-side fix, but it may be fine if other users of the CFG are fine with expanding.

It might be also possible to deep-copy the expressions when expanding. But in case of CXXDefaultArgExpr it would assume deep-copying arbitrary expressions, which sounds hard.



Yes, you are right; To be honest, I wasn’t previously familiar with that part of the codebase.
Yet still, those are very simple replacements, and IIRC those are the only two.

Supporting structured bindings would be indeed easier if we could have a simpler AST,
could you give an advice on what would be an equivalent AST we should rewrite to?

You should rewrite a DeclRefExpr denoting a BindingDecl into the binding expression (BindingDecl::getBinding()) of that binding.
 
Would producing a MemberExpr reading from the struct at *use* time be completely semantically equivalent?

Yes.
 
My previous impression was that for structured bindings load from the struct happens when the binding occurs,
not when the actual read is performed.
[though of course such rewrites would impede producing good diagnostic messages for the user]

The member access happens each time the binding is named, not up-front.

(However, for a tuple-like class type -- eg, std::tuple<...> or std::pair<...> -- the binding declarations have expressions that denote auxiliary variables (BindingDecl::getHoldingVar()) which are initialized up-front. In order to correctly handle those cases, when you build the CFG for a DecompositionDecl, you'll need to walk its bindings, check for holding variables, and also build CFG for those variables. You can search for "getHoldingVar()" through the clang codebase to see the other places this is already done -- in CodeGen and the constant expression evaluator.)
 
The BindingDecls should not even show up, except as sugar so that clients who care can know that the 'e.x' expression was /written as/ 'v'.
I'd imagine this is best modeled by generating CFG nodes for the subexpression on each occurrence of such a DeclRefExpr, much like (IIRC) is done for CXXDefaultArgExpr and CXXDefaultInitExpr. That seems like it would not require too many special cases elsewhere.

(Perhaps the static analyzer needs more than that in order to produce more user-friendly diagnostics?)

We are not even there yet for structured bindings, just trying to make the analyzer understand them.




_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev



_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Getting DecompositionDecl from BindingDecl

Manuel Klimek via cfe-dev
On 2 April 2018 at 18:04, Artem Dergachev via cfe-dev <[hidden email]> wrote:
On 4/2/18 2:11 PM, Richard Smith via cfe-dev wrote:
On 2 April 2018 at 13:52, George Karpenkov via cfe-dev <[hidden email]> wrote:
Hi Richard,

Thanks for your reply!

On Mar 30, 2018, at 8:49 PM, Richard Smith <[hidden email]> wrote:



Right, sure, but I don’t have a convenient way to find that DecompositionDecl from a given BindingDecl,
and sometimes I need to act based on the BindingDecl alone.

Can you give an example?

Let’s say a structured binding is written into, and then some function is called, and then we read from that binding again.
If it was global, we have to assume any function call can invalidate it, but if it’s local and it wasn’t passed as a parameter,
chances are it will remain the same.

I think that will just work if you expand references to BindingDecls into their binding expressions: both before and after, you'll end up evaluating an lvalue denoting the same subobject of the DecompositionDecl.
It was chosen because it matches the semantic model desired by the designers of the feature. For example, you can't handle bitfields if you model structured bindings as reference variables.

This was a somewhat controversial decision, but it doesn't look like it's going to be reversed.
That's what the CFG for the above function should represent.

Sorry, I’m not sure what do you mean here: from my understanding, CFG does not transform AST inside statements (apart from maybe tiny syntactic things).

IIRC, the CFG expands CXXDefaultArgExprs and CXXDefaultInitExprs; this case is analogous to those.

Thank you for the explanation! I was also very confused.

We do expand CXXDefaultInitExprs for sema warnings CFG, but not for the CFG analyzer. We don't expand CXXDefaultArgExprs yet.

I have a concern, which is probably invalid, about expanding expressions that can appear more than once. So far in a lot of places (in the analyzer in particular) we've been relying on every expression appearing only once within a single CFG, which would no longer be the case if we expand CXXDefaultArgExprs or DeclRefExprs-to-BindingDecls.

In particular, in the analyzer it's common to keep track of "the value of the expression". We are unable to handle the situation when the same expression, within the same call stack frame, in the same moment of time, has two different values. For BindingDecl this shouldn't be a problem because its expression will always have the same value.

Yes, a BindingDecl should always evaluate to the same lvalue throughout its lifetime (at least, per the current language rules; there's been some discussion of changing the semantics so that get<N>(e) is evaluated each time the binding is named, but so far that looks unlikely to happen).
 
For CXXDefaultArgExpr it seems to also not be a problem because it is always surrounded by its respective function call, which is already the next moment of time - and we won't expand the same CXXDefaultArgExpr twice in the same call. Even if CXXDefaultArgExpr calls itself recursively, we're not on the same stack frame anymore.

Interesting, you evaluate default arguments in the callee's stack frame? (We've historically had problems with this in the constant expressoin evaluator, where we're now numbering "versions" of variables and temporaries to distinguish them in situations like this -- see https://reviews.llvm.org/D42776). It's not completely clear to me that you can't need to have the same CXXDefaultArgExpr live twice at the same time; a construct like:

int f(int a = f(0), int b = g());
f();

... would trigger that if it were valid, and it's conceivable that there are variants of that which are valid.

Am i understanding correctly that we're not ever going to be required to maintain two different values for CXXDefaultArgExpr sub-expressions or for binding sub expressions? Is there something that protects us from such situations, apart from "that's where we are at the moment"?

Good question. I don't think so. And we already can't rely on that for CXXDefaultInitExprs.
 
The other problem i'm immediately seeing in the analyzer is to prevent it from thinking that we've found an infinite loop when we visit the same expression twice without any change in the state of the program (which is a known but presumably relatively harmless bug in our current CXXDefaultArgExpr handling). But that should be relatively easy to resolve.

There is also a certain amount of "unknown unknowns" here, because i've no idea in how many other places we rely upon, or will need to rely upon every expression appearing only once.

The alternative i've been considering for now was to provide "fake stack frames" for evaluating such expandable expressions instead of expanding them directly into the CFG. This would be an analyzer-side fix, but it may be fine if other users of the CFG are fine with expanding.

It might be also possible to deep-copy the expressions when expanding. But in case of CXXDefaultArgExpr it would assume deep-copying arbitrary expressions, which sounds hard.

Yes. Another option might be to stop using the Expr* to identify the CFG element / value, but I suspect that would be a very substantial undertaking?
 
Yes, you are right; To be honest, I wasn’t previously familiar with that part of the codebase.
Yet still, those are very simple replacements, and IIRC those are the only two.

Supporting structured bindings would be indeed easier if we could have a simpler AST,
could you give an advice on what would be an equivalent AST we should rewrite to?

You should rewrite a DeclRefExpr denoting a BindingDecl into the binding expression (BindingDecl::getBinding()) of that binding.
 
Would producing a MemberExpr reading from the struct at *use* time be completely semantically equivalent?

Yes.
 
My previous impression was that for structured bindings load from the struct happens when the binding occurs,
not when the actual read is performed.
[though of course such rewrites would impede producing good diagnostic messages for the user]

The member access happens each time the binding is named, not up-front.

(However, for a tuple-like class type -- eg, std::tuple<...> or std::pair<...> -- the binding declarations have expressions that denote auxiliary variables (BindingDecl::getHoldingVar()) which are initialized up-front. In order to correctly handle those cases, when you build the CFG for a DecompositionDecl, you'll need to walk its bindings, check for holding variables, and also build CFG for those variables. You can search for "getHoldingVar()" through the clang codebase to see the other places this is already done -- in CodeGen and the constant expression evaluator.)
 
The BindingDecls should not even show up, except as sugar so that clients who care can know that the 'e.x' expression was /written as/ 'v'.
I'd imagine this is best modeled by generating CFG nodes for the subexpression on each occurrence of such a DeclRefExpr, much like (IIRC) is done for CXXDefaultArgExpr and CXXDefaultInitExpr. That seems like it would not require too many special cases elsewhere.

(Perhaps the static analyzer needs more than that in order to produce more user-friendly diagnostics?)

We are not even there yet for structured bindings, just trying to make the analyzer understand them.




_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev



_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev



_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev
Reply | Threaded
Open this post in threaded view
|

Re: Getting DecompositionDecl from BindingDecl

Manuel Klimek via cfe-dev


On 4/2/18 6:25 PM, Richard Smith wrote:
On 2 April 2018 at 18:04, Artem Dergachev via cfe-dev <[hidden email]> wrote:
On 4/2/18 2:11 PM, Richard Smith via cfe-dev wrote:
On 2 April 2018 at 13:52, George Karpenkov via cfe-dev <[hidden email]> wrote:
Hi Richard,

Thanks for your reply!

On Mar 30, 2018, at 8:49 PM, Richard Smith <[hidden email]> wrote:



Right, sure, but I don’t have a convenient way to find that DecompositionDecl from a given BindingDecl,
and sometimes I need to act based on the BindingDecl alone.

Can you give an example?

Let’s say a structured binding is written into, and then some function is called, and then we read from that binding again.
If it was global, we have to assume any function call can invalidate it, but if it’s local and it wasn’t passed as a parameter,
chances are it will remain the same.

I think that will just work if you expand references to BindingDecls into their binding expressions: both before and after, you'll end up evaluating an lvalue denoting the same subobject of the DecompositionDecl.
It was chosen because it matches the semantic model desired by the designers of the feature. For example, you can't handle bitfields if you model structured bindings as reference variables.

This was a somewhat controversial decision, but it doesn't look like it's going to be reversed.
That's what the CFG for the above function should represent.

Sorry, I’m not sure what do you mean here: from my understanding, CFG does not transform AST inside statements (apart from maybe tiny syntactic things).

IIRC, the CFG expands CXXDefaultArgExprs and CXXDefaultInitExprs; this case is analogous to those.

Thank you for the explanation! I was also very confused.

We do expand CXXDefaultInitExprs for sema warnings CFG, but not for the CFG analyzer. We don't expand CXXDefaultArgExprs yet.

I have a concern, which is probably invalid, about expanding expressions that can appear more than once. So far in a lot of places (in the analyzer in particular) we've been relying on every expression appearing only once within a single CFG, which would no longer be the case if we expand CXXDefaultArgExprs or DeclRefExprs-to-BindingDecls.

In particular, in the analyzer it's common to keep track of "the value of the expression". We are unable to handle the situation when the same expression, within the same call stack frame, in the same moment of time, has two different values. For BindingDecl this shouldn't be a problem because its expression will always have the same value.

Yes, a BindingDecl should always evaluate to the same lvalue throughout its lifetime (at least, per the current language rules; there's been some discussion of changing the semantics so that get<N>(e) is evaluated each time the binding is named, but so far that looks unlikely to happen).
 
For CXXDefaultArgExpr it seems to also not be a problem because it is always surrounded by its respective function call, which is already the next moment of time - and we won't expand the same CXXDefaultArgExpr twice in the same call. Even if CXXDefaultArgExpr calls itself recursively, we're not on the same stack frame anymore.

Interesting, you evaluate default arguments in the callee's stack frame?

We evaluate the default arguments in the caller stack frame before jumping into the callee stack frame, and call destructors for them after we're back to the callee stack frame. Or rather plan to evaluate, because right now we aren't doing very sensible things anyway when the argument is not an ICE. I mean, we're not yet evaluating default arguments, but we're already having a very conservative evaluation of their respective destructors, which already suffers a bit from the expression agglutination problem because it relies on the CXXBindTemporaryExpr in their initializer expression.

In the analyzer we not only have "stack frames", but we have a generalized notion of "location context" which might represent a stack frame (which is necessary to avoid collisions of expression values during recursion) but it might as well represent an if-statement branch or a single loop iteration (it still helps us track local variable lifetime; this isn't in fact implemented yet, but it was the original design). And we evaluate all expressions keeping in mind that we're in a certain location that is represented by the stack of "location contexts", which helps us de-duplicate expressions. So the solution of having a special "location context" for every CXXDefaultArgExpr, so that actual initialization expressions were isolated in their own environment and didn't collide, looks quite reliable / flexible / future-proof.

(We've historically had problems with this in the constant expressoin evaluator, where we're now numbering "versions" of variables and temporaries to distinguish them in situations like this -- see https://reviews.llvm.org/D42776). It's not completely clear to me that you can't need to have the same CXXDefaultArgExpr live twice at the same time; a construct like:

int f(int a = f(0), int b = g());
f();

Hmm, right, this sounds really scary. We aren't defended from this sort of things.

... would trigger that if it were valid, and it's conceivable that there are variants of that which are valid.

Am i understanding correctly that we're not ever going to be required to maintain two different values for CXXDefaultArgExpr sub-expressions or for binding sub expressions? Is there something that protects us from such situations, apart from "that's where we are at the moment"?

Good question. I don't think so. And we already can't rely on that for CXXDefaultInitExprs.

CXXDefaultInitExprs look safe to me because every member is initialized just once within a single constructor, and it also indeed stays within the constructor's stack frame together with their CXXCtorInitializers.

 
The other problem i'm immediately seeing in the analyzer is to prevent it from thinking that we've found an infinite loop when we visit the same expression twice without any change in the state of the program (which is a known but presumably relatively harmless bug in our current CXXDefaultArgExpr handling). But that should be relatively easy to resolve.

There is also a certain amount of "unknown unknowns" here, because i've no idea in how many other places we rely upon, or will need to rely upon every expression appearing only once.

The alternative i've been considering for now was to provide "fake stack frames" for evaluating such expandable expressions instead of expanding them directly into the CFG. This would be an analyzer-side fix, but it may be fine if other users of the CFG are fine with expanding.

It might be also possible to deep-copy the expressions when expanding. But in case of CXXDefaultArgExpr it would assume deep-copying arbitrary expressions, which sounds hard.

Yes. Another option might be to stop using the Expr* to identify the CFG element / value, but I suspect that would be a very substantial undertaking?

Yeah, that'd essentially involve deep-converting *every* statement into a whole new format of CFG elements and it'd make the CFG much more complex.

If we want to avoid manipulating expressions directly, we need to teach our CFG to answer questions like "here's the expression i'm trying to evaluate, what CFG elements correspond to its respective sub-expressions?", which constitutes a large chunk of the Stmt hierarchy complexity. And poor-man's solutions like CFGStmtMap wouldn't cut it as an answer because the whole point, to begin with, is to de-duplicate potentially repeating expressions, so we can't use those as keys anymore.

Yes, you are right; To be honest, I wasn’t previously familiar with that part of the codebase.
Yet still, those are very simple replacements, and IIRC those are the only two.

Supporting structured bindings would be indeed easier if we could have a simpler AST,
could you give an advice on what would be an equivalent AST we should rewrite to?

You should rewrite a DeclRefExpr denoting a BindingDecl into the binding expression (BindingDecl::getBinding()) of that binding.
 
Would producing a MemberExpr reading from the struct at *use* time be completely semantically equivalent?

Yes.
 
My previous impression was that for structured bindings load from the struct happens when the binding occurs,
not when the actual read is performed.
[though of course such rewrites would impede producing good diagnostic messages for the user]

The member access happens each time the binding is named, not up-front.

(However, for a tuple-like class type -- eg, std::tuple<...> or std::pair<...> -- the binding declarations have expressions that denote auxiliary variables (BindingDecl::getHoldingVar()) which are initialized up-front. In order to correctly handle those cases, when you build the CFG for a DecompositionDecl, you'll need to walk its bindings, check for holding variables, and also build CFG for those variables. You can search for "getHoldingVar()" through the clang codebase to see the other places this is already done -- in CodeGen and the constant expression evaluator.)
 
The BindingDecls should not even show up, except as sugar so that clients who care can know that the 'e.x' expression was /written as/ 'v'.
I'd imagine this is best modeled by generating CFG nodes for the subexpression on each occurrence of such a DeclRefExpr, much like (IIRC) is done for CXXDefaultArgExpr and CXXDefaultInitExpr. That seems like it would not require too many special cases elsewhere.

(Perhaps the static analyzer needs more than that in order to produce more user-friendly diagnostics?)

We are not even there yet for structured bindings, just trying to make the analyzer understand them.




_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev

_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev



_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev


_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev




_______________________________________________
cfe-dev mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-dev