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

Fletcher, John P j.p.fletcher at aston.ac.uk
Tue Apr 26 00:40:03 PDT 2011


Larrise

Where can I get the updated version, please.

John

________________________________
From: cfe-dev-bounces at cs.uiuc.edu [cfe-dev-bounces at cs.uiuc.edu] on behalf of Larisse Voufo [lvoufo at cs.indiana.edu]
Sent: 26 April 2011 02:57
To: Douglas Gregor
Cc: Andrew Lumsdaine; Jeremiah Willcock; cfe-dev at cs.uiuc.edu
Subject: Re: [cfe-dev] Working with ConceptClang: Binding input arguments to functions.

Issue resolved.

It turns out that my mistake was in the way I was (1) copying the implementation of associated functions over from concept definitions to their concept maps, and then (2) instantiating that concept map's implementation.
Basically, after substituting the types on the associated function, since the instantiation was treating the function itself as its own "pattern", I should have been substituting the types on the function's body as well somehow...
But this did not look like a very trivial move...

On the other hand, it was much easier to (1) keep records of the original implementations of those associated functions, before type substitution, and then (2) to treat those original implementations as the "patterns" needed during instantiation...

Anyway, I hope this makes sense somehow. But I did make these changes, and everything works perfectly! :)

Thanks for the help!

-- Larisse.



On Fri, Apr 22, 2011 at 12:57 PM, Larisse Voufo <lvoufo at cs.indiana.edu<mailto:lvoufo at cs.indiana.edu>> wrote:


On Fri, Apr 22, 2011 at 12:38 PM, Douglas Gregor <dgregor at apple.com<mailto: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<mailto: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






More information about the cfe-dev mailing list