Doubt about AST

$ cat y1.cc
template <typename T>
struct S {
  int operator=(int v);
  int f() {
    return *this = 2;
  }
};

$ ~/llvm/Debug/bin/clang -cc1 -ast-dump y1.cc
typedef char *__builtin_va_list;
template <typename T> struct S {
    struct S;
    int operator=(int v);
    int f() (CompoundStmt 0xa839ed0 <y1.cc:4:11, line:6:3>
  (ReturnStmt 0xa839eb8 <line:5:5, col:20>
    (BinaryOperator 0xa839e90 <col:12, col:20> '<dependent type>' '='
      (CXXOperatorCallExpr 0xa839e40 <col:12, col:13> '<dependent type>'
        (UnresolvedLookupExpr 0xa839e08 <col:12> '<dependent type>'
(ADL) = '1' empty)
        (CXXThisExpr 0xa839de8 <col:13> 'S<T> *' this))
      (IntegerLiteral 0xa839e68 <col:20> 'int' 2))))

};

I'd like to understand why *this is converted in CXXOperatorCallExpr of
UnresolvedLookupExpr instead of UnaryOperator deref.

The deref operator for this might be overloaded? How?

I'd like also to understand in which situations clang choose to emit
something like BinaryOperator (then instantiated in operator call) and
when choose to emit an operator call also on primary template (of course
when both choices might be done).

$ cat y1.cc
template <typename T>
struct S {
int operator=(int v);
int f() {
   return *this = 2;
}
};

$ ~/llvm/Debug/bin/clang -cc1 -ast-dump y1.cc
typedef char *__builtin_va_list;
template <typename T> struct S {
   struct S;
   int operator=(int v);
   int f() (CompoundStmt 0xa839ed0 <y1.cc:4:11, line:6:3>
(ReturnStmt 0xa839eb8 <line:5:5, col:20>
   (BinaryOperator 0xa839e90 <col:12, col:20> '<dependent type>' '='
     (CXXOperatorCallExpr 0xa839e40 <col:12, col:13> '<dependent type>'
       (UnresolvedLookupExpr 0xa839e08 <col:12> '<dependent type>'
(ADL) = '1' empty)
       (CXXThisExpr 0xa839de8 <col:13> 'S<T> *' this))
     (IntegerLiteral 0xa839e68 <col:20> 'int' 2))))

};

I'd like to understand why *this is converted in CXXOperatorCallExpr of
UnresolvedLookupExpr instead of UnaryOperator deref.

The deref operator for this might be overloaded? How?

Clang is seeing that the type of 'this' is dependent, so it uses the general type-dependent representation of a dereference operation, which is the CXXOperatorCallExpr you see there. We could perform a little more analysis to determine that it has pointer type and, therefore, actually build a UnaryOperator... but I don't know that it would make a big difference. Maybe it would matter for something like

  (*this).getAs<T>()

because we'd actually know the type of *this.

I'd like also to understand in which situations clang choose to emit
something like BinaryOperator (then instantiated in operator call) and
when choose to emit an operator call also on primary template (of course
when both choices might be done).

In non-dependent cases, BinaryOperator is for builtin types and CXXOperatorCallExpr is for uses of overloaded operators.

In dependent cases, we use CXXOperatorCallExpr when name lookup has found overloaded operators in the current scope, because we need to save those overloaded operators until instantiation time. (These are results from the first "phase" of two-phase name lookup). If no overloaded operators were found, we use BinaryOperator instead.

UnaryOperator should be doing the same thing here... so yes, there's a bug here :slight_smile:

  - Doug

Fixed in r106222.

I didn't try to teach Clang about the return type of *this when 'this' is dependent. It's not clear that we're actually allowed by the standard to do such a thing.

  - Doug