[llvm-branch-commits] [clang] release/22.x: [Clang] Don't diagnose missing members when looking at the instantiating class template (PR #183271)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Wed Feb 25 02:23:38 PST 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Younan Zhang (zyn0217)

<details>
<summary>Changes</summary>

This fixes a regression in Clang 21, which broke the build of qt5-webengine on some platforms. So I'm going to backport 924f773f5 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.



---
Full diff: https://github.com/llvm/llvm-project/pull/183271.diff


3 Files Affected:

- (modified) clang/docs/ReleaseNotes.rst (+1) 
- (modified) clang/lib/Sema/SemaExpr.cpp (+1-1) 
- (modified) clang/test/SemaCXX/overload-resolution-deferred-templates.cpp (+81) 


``````````diff
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, "");
+
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/183271


More information about the llvm-branch-commits mailing list