Author: Arthur O'Dwyer Date: 2022-01-27T14:21:50-05:00 New Revision: 9be5f4d5afd9a1b6e88a268f6ea6eb282d77d9fe
URL: https://github.com/llvm/llvm-project/commit/9be5f4d5afd9a1b6e88a268f6ea6eb282d77d9fe DIFF: https://github.com/llvm/llvm-project/commit/9be5f4d5afd9a1b6e88a268f6ea6eb282d77d9fe.diff LOG: [clang] Don't typo-fix an expression in a SFINAE context. If this is a SFINAE context, then continuing to look up names (in particular, to treat a non-function as a function, and then do ADL) might too-eagerly complete a type that it's not safe to complete right now. We should just say "okay, that's a substitution failure" and not do any more work than absolutely required. Fixes #52970. Differential Revision: https://reviews.llvm.org/D117603 Added: clang/test/SemaCXX/PR52970.cpp Modified: clang/lib/Sema/Sema.cpp clang/lib/Sema/SemaExprMember.cpp Removed: ################################################################################ diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index a5a62276043dc..20b4a9a5d4e6c 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -2554,6 +2554,11 @@ static bool IsCPUDispatchCPUSpecificMultiVersion(const Expr *E) { 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 index f67ef030feb70..dfd93aa4638d2 100644 --- a/clang/lib/Sema/SemaExprMember.cpp +++ b/clang/lib/Sema/SemaExprMember.cpp @@ -1645,6 +1645,9 @@ static ExprResult LookupMemberExpr(Sema &S, LookupResult &R, << 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 index 0000000000000..fcbb61af18e6a --- /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 <class T> struct Holder { T t; }; + +namespace DotFollowingFunctionName { +struct Good { + struct Nested { + int b; + } a; +}; + +struct Bad { + Holder<Incomplete> a(); +}; + +template <class T> +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 <class T> +concept C = requires(T t) { t.a.b; }; + +static_assert(C<Good>); +static_assert(!C<Bad>); +#endif +} // namespace DotFollowingFunctionName + +namespace DotFollowingPointer { +struct Good { + int begin(); +}; +using Bad = Holder<Incomplete> *; + +template <class T> +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 <class T> +concept C = requires(T t) { t.begin(); }; + +static_assert(C<Good>); +static_assert(!C<Bad>); +#endif +} // namespace DotFollowingPointer _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits