diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -2554,6 +2554,11 @@ bool Sema::tryToRecoverWithCall(ExprResult &E, const PartialDiagnostic &PD, bool ForceComplain, bool (*IsPlausibleResult)(QualType)) { + if (isSFINAEContext()) { + // If this is a SFINAE context, don't try anything that might trigger ADL + // prematurely. + return false; + } SourceLocation Loc = E.get()->getExprLoc(); SourceRange Range = E.get()->getSourceRange(); diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -1645,6 +1645,9 @@ << BaseType << int(IsArrow) << BaseExpr.get()->getSourceRange() << FixItHint::CreateReplacement(OpLoc, "->"); + if (S.isSFINAEContext()) + return ExprError(); + // Recurse as an -> access. IsArrow = true; return LookupMemberExpr(S, R, BaseExpr, IsArrow, OpLoc, SS, diff --git a/clang/test/SemaCXX/PR52970.cpp b/clang/test/SemaCXX/PR52970.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/PR52970.cpp @@ -0,0 +1,57 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify %s +// RUN: %clang_cc1 -fsyntax-only -std=c++14 -verify %s +// RUN: %clang_cc1 -fsyntax-only -std=c++17 -verify %s +// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s +// expected-no-diagnostics + +struct Incomplete; +template struct Holder { T t; }; + +namespace DotFollowingFunctionName { +struct Good { + struct Nested { + int b; + } a; +}; + +struct Bad { + Holder a(); +}; + +template +constexpr auto f(T t) -> decltype((t.a.b, true)) { return true; } +constexpr bool f(...) { return false; } + +static_assert(DotFollowingFunctionName::f(Good{}), ""); +static_assert(!DotFollowingFunctionName::f(Bad{}), ""); + +#if __cplusplus >= 202002L +template +concept C = requires(T t) { t.a.b; }; + +static_assert(C); +static_assert(!C); +#endif +} // namespace DotFollowingFunctionName + +namespace DotFollowingPointer { +struct Good { + int begin(); +}; +using Bad = Holder *; + +template +constexpr auto f(T t) -> decltype((t.begin(), true)) { return true; } +constexpr bool f(...) { return false; } + +static_assert(DotFollowingPointer::f(Good{}), ""); +static_assert(!DotFollowingPointer::f(Bad{}), ""); + +#if __cplusplus >= 202002L +template +concept C = requires(T t) { t.begin(); }; + +static_assert(C); +static_assert(!C); +#endif +} // namespace DotFollowingPointer