llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
29.42k stars 12.15k forks source link

SFINAEing `p.x` on a pointer wrongly tries to complete the pointee's type #52970

Closed Quuxplusone closed 2 years ago

Quuxplusone commented 2 years ago

This program hard-errors trying to complete Holder<Incomplete>; but it shouldn't.

struct Incomplete;
template<class T> struct Holder { T t; int x; };
template<class T> auto f(T t) -> decltype(t.x);
void f(...);
void test() {
    ::f((Holder<Incomplete>*)nullptr);
}

It appears to me that the problem is here, in LookupMemberExpr:

  // Recover from dot accesses to pointers, e.g.:
  //   type *foo;
  //   foo.bar
  [...]
    if (!IsArrow && Ptr->getPointeeType()->isRecordType() &&
        MemberName.getNameKind() != DeclarationName::CXXDestructorName) {
      S.Diag(OpLoc, diag::err_typecheck_member_reference_suggestion)
          << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange()
          << FixItHint::CreateReplacement(OpLoc, "->");

      // Recurse as an -> access.
      IsArrow = true;
      return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS,
                              ObjCImpDecl, HasTemplateArgs, TemplateKWLoc);
    }
  }

That second recursive call to LookupMemberExpr triggers completion of the pointed-to type, which is not OK if we're in a SFINAE context.

Quuxplusone commented 2 years ago

I've managed to fix this locally by adding

  if (S.isUnevaluatedContext())
    return ExprError();

after the S.Diag; but I don't know if there might be a less blunt instrument available.

Quuxplusone commented 2 years ago

This is now https://reviews.llvm.org/D117603

llvmbot commented 2 years ago

@llvm/issue-subscribers-clang-frontend