Explicit this expression in class template is dependent?

Hi all,

I find that explicit this expressions in class templates create a CXXDependentScopeMemberExpr in the AST while the equivalent implicit this is a MemberExpr. For example code like this:

template <typename T> struct A {
  int i;
  int getImplicit() { return i; } // MemberExpr
  int getExplicit() { return this->i; } // CXXDependentScopeMemberExpr
};

Why is explicit dependent? Is it technical (per the language standard) or an implementation detail? I’d like both expressions to resolve to the member for static analysis/refactoring/etc.

Jason

I think the only way this could be dependent is if you have dependent bases, but there may be awkward cases I haven’t thought about.

Consider this code in SemaExprMember.cpp:

ExprResult
Sema::BuildMemberReferenceExpr(Expr *Base, QualType BaseType,
SourceLocation OpLoc, bool IsArrow,
CXXScopeSpec &SS,
SourceLocation TemplateKWLoc,
NamedDecl *FirstQualifierInScope,
const DeclarationNameInfo &NameInfo,
const TemplateArgumentListInfo *TemplateArgs,
ActOnMemberAccessExtraArgs *ExtraArgs) {
if (BaseType->isDependentType() ||
(SS.isSet() && isDependentScopeSpecifier(SS)))
return ActOnDependentMemberExpr(Base, BaseType,
IsArrow, OpLoc,
SS, TemplateKWLoc, FirstQualifierInScope,
NameInfo, TemplateArgs);

Perhaps it could look at the BaseType to see if it is a record decl that does not have any dependent bases, and in that case form a regular MemberExpr.

In the implicit case, i is unqualified and ADL doesn’t fire, so it can’t be dependent.

$ cat ct.cc

template <typename T> struct A {
  int getExplicit() { return this->i; } // might compile
  int getImplicit() { return i; } // must not compile
};

$ clang++ -std=c++11 -c ct.cc
ct.cc:4:30: error: use of undeclared identifier 'i'
  int getImplicit() { return i; } // MemberExpr
                             ^
1 error generated.

Lookup in "return i;" is done in phase one, when the template is
parsed. `i` isn't there, so it's an error. Lookup in "return
this->i;" is done in phase two, at template instantiation time. If
there were dependent base classes, "return this->i" could find things
in them, while "return i" would not.

There is a rule that allows Clang to give an error for `getExplicit`
also -- the rule that says that a template (/temploid) is ill-formed
(no diagnostic required) if there is no possible well-formed
instantiation of it.

It would also be convenient for tools if Clang became a little more
aggressive in noticing that "return this->i" isn't dependent in any
meaningful way in the code above, given that there are no dependent
base classes.

Okay, thanks for the explanation guys! I think I understand. I may try to propose a patch along those lines (construct MemberExpr in classes without dependent bases) if I find that I’m not too far out of my depth.

Jason