[clang] [Clang] Don't diagnose missing members when looking at the instantiating class template (PR #180725)
Younan Zhang via cfe-commits
cfe-commits at lists.llvm.org
Tue Feb 10 03:37:20 PST 2026
https://github.com/zyn0217 created https://github.com/llvm/llvm-project/pull/180725
The perfect matching patch revealed another bug where recursive instantiations could lead to the escape of SFINAE errors, as shown in the issue.
I intend to backport this to Clang 22, so I will include a release note during the backporting process.
Fixes https://github.com/llvm/llvm-project/issues/179118
>From e3c2b3025f03770ad7e58c7ad3183f4e050f2933 Mon Sep 17 00:00:00 2001
From: Younan Zhang <zyn7109 at gmail.com>
Date: Tue, 10 Feb 2026 19:26:32 +0800
Subject: [PATCH] [Clang] Don't diagnose missing members when looking at the
instantiating class template
The perfect matching patch revealed another bug where recursive
instantiations could lead to the escape of SFINAE errors, as shown in
the issue.
I intend to backport this to Clang 22, so I will include a release note
during the backporting process.
---
clang/lib/Sema/SemaExpr.cpp | 2 +-
...overload-resolution-deferred-templates.cpp | 81 +++++++++++++++++++
2 files changed, 82 insertions(+), 1 deletion(-)
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 5795a71b5cae8..f27de8de04f7a 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -2938,7 +2938,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, "");
+
+}
More information about the cfe-commits
mailing list