[cfe-dev] Identifiying (successfully resolved) overloaded function references.

Enea Zaffanella zaffanella at cs.unipr.it
Wed Oct 5 09:01:57 PDT 2011


Il 05/10/2011 08:26, John McCall ha scritto:
> On Oct 4, 2011, at 11:21 PM, Enea Zaffanella wrote:
>> Il 03/10/2011 09:50, Enea Zaffanella ha scritto:
>>> Il 30/09/2011 11:57, John McCall ha scritto:
>>>> On Sep 30, 2011, at 2:19 AM, Enea Zaffanella wrote:
>>>>> We would like to identify the DeclRefExpr and MemberExpr AST nodes
>>>>> that have been created by looking up an overloaded function reference.
>>>>> As far as we can tell, there is no way to extract this information
>>>>> from the current AST. (Is such an impression correct?)
>>
>> [...]
>>
>>> Please find attached a patch for review.
>>
>> No comments?
>> OK to commit?
> 
> It looks fine to me if you're sure this is useful to you.  Please do remove
> it if you find that it doesn't actually help.
> 
> John.
> 


OK, committed in r141171.

Regarding its usefulness, our immediate use of this flag is to
distinguish those explicit casts applied to function (pointer)
references that are meant to "implement" overload resolution.


/***********************************************
Start of example that can be skipped if not really interested in
details, but please do read below example if skipping
***********************************************/

As an example, consider the following chunk of code:

bool operator< (const S&, const S&);
bool operator< (const T&, const T&);

typedef bool (*CMP)(const S&, const S&);

template <typename Iter, typename Pred>
bool is_sorted(Iter first, Iter last, Pred cmp);

void test(const std::vector<S>& vs) {
  is_sorted(vs.begin(), vs.end(), static_cast<CMP>(operator<));
}

Here the static_cast is needed, because there are multiple candidates
when resolving "operator<". Otherwise, if there were a single candidate,
then the cast would not have been needed.

The AST in clang (for the relevant portion of code) for both the cases
(single candidate or multiple candidates) is

    (CXXStaticCastExpr 0x444c960 <col:35, col:61> 'CMP':'_Bool (*)(const
struct S &, const struct S &)' static_cast<CMP> <NoOp>
      (ImplicitCastExpr 0x444c948 <col:52, <invalid sloc>> '_Bool
(*)(const struct S &, const struct S &)' <FunctionToPointerDecay>
        (DeclRefExpr 0x444c920 <col:52, <invalid sloc>> '_Bool (const
struct S &, const struct S &)' lvalue Function 0x442f1d0 'operator<'
'_Bool (const struct S &, const struct S &)')))))

In the two cases, we have two NoOp explicit casts and the added flag
allows us to distinguish between them.

/***********************************************
End of example that can be skipped
***********************************************/


Would there be objections to the "splitting" of the current NoOp cast
kind into a few, slightly different flavors of NoOp providing a clearer
distinction, that will be useful for source code based tools?

For instance, in the case of the example above, the explicit NoOp
static_cast kind could be replaced (when there are indeed multiple
candidates) by an "OverloadResolution" cast kind.

Another example is that of (usually implicit) NoOp casts resulting from
qualification conversions, i.e., when the "const" qualifier is added to
a modifiable lvalue argument expression passed to a function by const&:
in this case, we would opt for a "QualificationConversion" cast kind.

The final goal would be to have a NoOp cast kind only for those casts
that are NoOp under all points of view: no change for the type, no
change for the value and no change for the lvalue-ness of the argument
expression.

Clearly, the new "source code based" cast kinds will be treated in
other compilation phases as if they were plain NoOp.
(If deemed useful, for clarity, we can even uses names such as
NoOp_OverloadResolution and NoOp_QualificationConversion).

Opinions?

Enea.



More information about the cfe-dev mailing list