[cfe-dev] Working with ConceptClang: Binding input arguments to functions.

Larisse Voufo lvoufo at cs.indiana.edu
Fri Apr 22 09:57:51 PDT 2011


On Fri, Apr 22, 2011 at 12:38 PM, Douglas Gregor <dgregor at apple.com> wrote:

>
> On Apr 22, 2011, at 9:27 AM, Larisse Voufo wrote:
>
>
>
> On Fri, Apr 22, 2011 at 11:51 AM, Douglas Gregor <dgregor at apple.com>wrote:
>
>>
>> On Apr 22, 2011, at 2:05 AM, Larisse Voufo wrote:
>>
>> Here's a basic example I've been trying to get to work:
>>
>> explicit concept A<typename T> {
>>     typename AType;
>>
>>     AType h(AType a) {
>>         return a;
>>     }
>>
>>     AType f(AType a) {
>>         AType b;
>>         return b;
>>     }
>> }
>>
>> concept_map A<int> {
>>     typedef char AType;
>> }
>>
>> template<typename T>
>> requires (A<T>)
>> void func(T a, AType b) {
>>     AType x = h(b);         // <-- Instantiation DOES NOT WORK
>>     AType y = f(b);          // <-- Instantiation WORKS
>> }
>>
>> int main(int argc, char **argv)
>> {
>>     func<int>(10, 'a');      // Fails with declaration for 'x', for passes
>> with declaration of 'y'.
>> }
>>
>>
>> It appears that during the instantiation of *func<int>()*, the value for
>> input parameter '*b*' for '*func()*'
>> can be looked up no problem. However, that of '*a*' for associated
>> function '*h()*' cannot.
>> Instead, a call to *clang::LocalInstantiationScope::getInstantiationOf()*fails at runtime on the assertion:
>>
>> *(D->isInvalidDecl() && "declaration was not instantiated in this
>> scope!")*.
>>
>> I have been tracing through the procedures for building, transforming, and
>> rebuilding Call Expressions -- as well as instantiating functions, noting
>> each
>> execution of *clang::LocalInstantiationScope::getInstantiationOf()* and *
>> clang::LocalInstantiationScope::InstantiatedLocal()*...
>>
>> Still, I can't see what needs to be done differently for calls to *h()*from calls to
>> *func<int>()*. Hence...
>>
>> Question:
>> When/how exactly are input arguments bound to functions?
>>
>>
>> That's a runtime issue. All the front-end does is enforce the calling
>> convention on both sides of the call.
>>
>
> And how does it do that? Exactly, when is *func<int>*'s '*b*' supposed to
> meet *h*'s '*a*'?
> Just as... When do the *main*'s *10* and '*a*' meet *func<int>*'s '*a*'
> and '*b*' ?
>
>
> At run time, the caller puts the call arguments into registers and on the
> stack, and executes a call instruction. The Clang front-end never does this;
> optimization passes may do it at the IR level.
>
>
>> Why would the current procedure fail to bind the value of '*b*' from the
>> context of *func<int>* to the
>> parameter '*a*' of *h* ?
>>
>>
>> They are in completely different contexts. func<int>'s b is completely
>> disjoint from h's a. And, in fact, they might not be the same thing, since
>> passing 'b' as an argument to h() implies the creation of a temporary.
>>
>> The only way I could see this issue coming up is if you're doing some kind
>> of inlining of A<AType>::h into func<int> as part of instantiation. If so, I
>> recommend against doing that: inlining will be handled by later optimization
>> passes, and tangling the func<int> instantiation with the A<AType>::h
>> instantiation is going to cause more problems in the front end than it
>> solves.
>>
>
> Hmm... How would the call be handled if *h* was a global function -- a
> specialization of some template, not associated with any concept?
>
>
> Exactly the same here.
>
> I am not trying to achieve any inlining here, I just want to pass in the
> arguments as I would any inner function call (though thanks for the tip)...
>
>
> You don't need to do any argument passing. Let Clang do that for you. All
> you need to do is trigger the right instantiation.
>

I believe I'm doing exactly what should be done with any function call, i.e.
rebuilding the call expressions et al. -- after hijacking the callee pointer
so it points to the appropriate concept's associated function
implementation.
Apparently, in the way that I'm currently using Clang, it is not doing a
very good job at taking care of things for me, and I am not sure which
"parameters" I may have overlooked.

I notice that the transformation of a call expression (via TreeTransform<>::
TransformCallExpr)  transforms both the callee and the arguments. I am doing
just that after redefining the callee...
Somehow, this looses the temporaries instantiation that happens for normal
function calls...
Note that when I run examples where h is global, it works... But when I put
h in a concept, it doesn't.
The local instantiation scope for the instantiation of h somehow can pick up
any local variable, but not it's parameters...
and this only happens in cases where h is in a concept context.

Is there something that ActOnCallExpr does that is dependent on the calling
context that I am overlooking?
I'm really not sure how to diagnose this issue anymore... :-/

A quick hack that i could do, is explicitly inject an instantiation of
function parameters after/while transforming the call expression. But I'm
not sure (don't think) this is a good idea, as -- like you said -- Clang
should automatically take care of this for me.

What do you think? I'll keep thinking about this, but thanks for your help
already.



>
> - Doug
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.llvm.org/pipermail/cfe-dev/attachments/20110422/4ae0c9b7/attachment.html>


More information about the cfe-dev mailing list