Author: Younan Zhang Date: 2026-02-28T09:15:42Z New Revision: 1e66cb3c2e6e21dad7bc7a18b1825cd0c762ac86
URL: https://github.com/llvm/llvm-project/commit/1e66cb3c2e6e21dad7bc7a18b1825cd0c762ac86 DIFF: https://github.com/llvm/llvm-project/commit/1e66cb3c2e6e21dad7bc7a18b1825cd0c762ac86.diff LOG: [Clang] Don't diagnose missing members when looking at the instantiating class template This backports https://github.com/llvm/llvm-project/pull/180725 to Clang 22. The perfect matching patch revealed another bug where recursive instantiations could lead to the escape of SFINAE errors, as shown in the issue. Added: Modified: clang/docs/ReleaseNotes.rst clang/lib/Sema/SemaExpr.cpp clang/test/SemaCXX/overload-resolution-deferred-templates.cpp Removed: ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 7ac3e272beff2..aecbff4baf678 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -655,6 +655,7 @@ Bug Fixes to C++ Support - Fixed a crash when parsing the ``enable_if`` attribute on C function declarations with identifier-list parameters. (#GH173826) - Fixed an assertion failure triggered by nested lambdas during capture handling. (#GH172814) - Fixed an assertion failure in vector conversions involving instantiation-dependent template expressions. (#GH173347) +- Fixed an issue where recursive instantiation could lead to escape of SFINAE errors. (#GH179118) - Fixed an assertion failure in floating conversion narrowing caused by C++ constant expression checks in C23 mode. (#GH173847) Bug Fixes to AST Handling diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 4d787a60eba3b..270b82ef38b83 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -2937,7 +2937,7 @@ ExprResult Sema::BuildQualifiedDeclarationNameExpr( // members were likely supposed to be inherited. DeclContext *DC = computeDeclContext(SS); if (const auto *CD = dyn_cast<CXXRecordDecl>(DC)) - if (CD->isInvalidDecl()) + if (CD->isInvalidDecl() || CD->isBeingDefined()) return ExprError(); Diag(NameInfo.getLoc(), diag::err_no_member) << NameInfo.getName() << DC << SS.getRange(); diff --git a/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp b/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp index c3bda3988484d..acd38b37c3b5c 100644 --- a/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp +++ b/clang/test/SemaCXX/overload-resolution-deferred-templates.cpp @@ -310,3 +310,84 @@ void test() { } } + +namespace GH179118 { + +namespace std { + +template <bool __v> struct integral_constant { + static constexpr bool value = __v; +}; + +template <typename _Tp, typename... _Args> +using __is_constructible_impl = + integral_constant<__is_constructible(_Tp, _Args...)>; + +template <typename _Tp, typename... _Args> +struct is_constructible : public std::__is_constructible_impl<_Tp, _Args...> {}; + +template <bool> struct _cond { + template <typename Then, typename> using invoke = Then; +}; +template <> struct _cond<false> { + template <typename, typename Else> using invoke = Else; +}; + +template <bool If, typename Then, typename Else> +using conditional_t = typename _cond<If>::template invoke<Then, Else>; + +template <bool, class _Tp = void> struct enable_if; +template <class _Tp> struct enable_if<true, _Tp> { + typedef _Tp type; +}; +template <bool _Bp, class _Tp = void> +using enable_if_t = typename enable_if<_Bp, _Tp>::type; + +} // namespace std + +namespace base { + +template <typename...> struct disjunction {}; +template <typename B1, typename... Bn> +struct disjunction<B1, Bn...> + : std::conditional_t<B1::value, B1, disjunction<>> {}; +template <typename> class Optional; + +namespace internal { +template <typename T, typename U> +using IsConvertibleFromOptional = + disjunction<std::is_constructible<T, Optional<U> &>>; +template <typename T, typename U> +using IsAssignableFromOptional = IsConvertibleFromOptional<T, U>; +} // namespace internal + +template <typename T> class Optional { +public: + Optional(Optional &&); + + template <typename U, + std::enable_if_t<internal::IsConvertibleFromOptional<T, U>::value> = + false> + Optional(Optional<U>); + + Optional(const Optional &); + void operator=(Optional &&); + + template <typename U> + std::enable_if_t<std::is_constructible<T, U>::value> operator=(U &&); + + template <typename U> + std::enable_if_t<internal::IsAssignableFromOptional<T, U>::Optional> + operator=(Optional<U>); +}; + +} // namespace base + +struct LayoutUnit { + template <typename IntegerType> LayoutUnit(IntegerType); +}; + +static_assert( + std::is_constructible<LayoutUnit, base::Optional<LayoutUnit> &>::value, ""); + +} _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
