[clang] [Clang] Instantiate variables referenced in `decltype` with an undeduced type. (PR #161231)

Corentin Jabot via cfe-commits cfe-commits at lists.llvm.org
Mon Sep 29 10:49:23 PDT 2025


https://github.com/cor3ntin updated https://github.com/llvm/llvm-project/pull/161231

>From 4c0152234c53fe7b97fcca65a61d4c29b611fb19 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Mon, 29 Sep 2025 18:55:22 +0200
Subject: [PATCH 1/5] [Clang] Instantiate variables referenced in `decltype`
 with an undeduced type.

Fixes #160497
---
 clang/docs/ReleaseNotes.rst     |  1 +
 clang/lib/Sema/SemaExpr.cpp     |  5 +++--
 clang/test/SemaCXX/decltype.cpp | 30 ++++++++++++++++++++++++++++++
 3 files changed, 34 insertions(+), 2 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index e8deae50e4cb0..df277a13e9f23 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -433,6 +433,7 @@ Bug Fixes to C++ Support
   object type. (#GH151531)
 - Suppress ``-Wdouble-promotion`` when explicitly asked for with C++ list initialization (#GH33409).
 - Fix the result of `__builtin_is_implicit_lifetime` for types with a user-provided constructor. (#GH160610)
+- Correctly deduced return types in ``decltype`` expressions. (#GH160497)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 3b267c1b1693d..3302bfce193a2 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -20108,8 +20108,9 @@ static void DoMarkVarDeclReferenced(
   bool NeededForConstantEvaluation =
       isPotentiallyConstantEvaluatedContext(SemaRef) && UsableInConstantExpr;
 
-  bool NeedDefinition =
-      OdrUse == OdrUseContext::Used || NeededForConstantEvaluation;
+  bool NeedDefinition = OdrUse == OdrUseContext::Used ||
+                        NeededForConstantEvaluation ||
+                        Var->getType()->isUndeducedType();
 
   assert(!isa<VarTemplatePartialSpecializationDecl>(Var) &&
          "Can't instantiate a partial template specialization.");
diff --git a/clang/test/SemaCXX/decltype.cpp b/clang/test/SemaCXX/decltype.cpp
index 739485b57a3ec..971cf5132d4d5 100644
--- a/clang/test/SemaCXX/decltype.cpp
+++ b/clang/test/SemaCXX/decltype.cpp
@@ -170,3 +170,33 @@ class conditional {
 // FIXME: The diagnostics here are produced twice.
 void foo(conditional<decltype((1),int>) {  // expected-note 2 {{to match this '('}} expected-error {{expected ')'}} expected-note 2{{to match this '<'}}
 } // expected-error {{expected function body after function declarator}} expected-error 2 {{expected '>'}} expected-error {{expected ')'}}
+
+
+namespace GH160497 {
+
+template <class> struct S {
+    template <class>
+    inline static auto mem =
+    [] { static_assert(false); // expected-error {{static assertion failed}} \
+        // expected-note {{while substituting into a lambda expression here}}
+        return 42;
+    }();
+};
+
+using T = decltype(S<void>::mem<void>);
+ // expected-note at -1 {{in instantiation of static data member 'GH160497::S<void>::mem<void>' requested here}}
+
+namespace N1 {
+
+template<class>
+struct S {
+  template<class>
+  inline static auto mem = 42;
+};
+
+using T = decltype(S<void>::mem<void>);
+
+T y = 42;
+
+}
+}

>From 83d1532dcf163fbfbc665244c152e117f85271c1 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Mon, 29 Sep 2025 19:11:21 +0200
Subject: [PATCH 2/5] fix tests

---
 clang/test/SemaCXX/decltype.cpp | 38 +++++++++++++++++----------------
 1 file changed, 20 insertions(+), 18 deletions(-)

diff --git a/clang/test/SemaCXX/decltype.cpp b/clang/test/SemaCXX/decltype.cpp
index 971cf5132d4d5..7931c6ac45429 100644
--- a/clang/test/SemaCXX/decltype.cpp
+++ b/clang/test/SemaCXX/decltype.cpp
@@ -1,4 +1,5 @@
 // RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify -Wno-c99-designator %s
+// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify -Wno-c99-designator %s
 
 // PR5290
 int const f0();
@@ -156,27 +157,12 @@ struct A {
   }
 };
 
-// This shouldn't crash.
-static_assert(A<int>().f<int>() == 0, "");
-// The result should not be dependent.
-static_assert(A<int>().f<int>() != 0, ""); // expected-error {{static assertion failed due to requirement 'GH99873::A<int>().f<int>() != 0'}}
-                                           // expected-note at -1 {{expression evaluates to '0 != 0'}}
-}
-
-template<typename>
-class conditional {
-};
-
-// FIXME: The diagnostics here are produced twice.
-void foo(conditional<decltype((1),int>) {  // expected-note 2 {{to match this '('}} expected-error {{expected ')'}} expected-note 2{{to match this '<'}}
-} // expected-error {{expected function body after function declarator}} expected-error 2 {{expected '>'}} expected-error {{expected ')'}}
-
-
+#if __cplusplus >= 201703L
 namespace GH160497 {
 
 template <class> struct S {
     template <class>
-    inline static auto mem =
+    static inline auto mem =
     [] { static_assert(false); // expected-error {{static assertion failed}} \
         // expected-note {{while substituting into a lambda expression here}}
         return 42;
@@ -184,7 +170,7 @@ template <class> struct S {
 };
 
 using T = decltype(S<void>::mem<void>);
- // expected-note at -1 {{in instantiation of static data member 'GH160497::S<void>::mem<void>' requested here}}
+ // expected-note at -1 {{in instantiation of static data member 'GH99873::GH160497::S<void>::mem<void>' requested here}}
 
 namespace N1 {
 
@@ -200,3 +186,19 @@ T y = 42;
 
 }
 }
+#endif
+
+// This shouldn't crash.
+static_assert(A<int>().f<int>() == 0, "");
+// The result should not be dependent.
+static_assert(A<int>().f<int>() != 0, ""); // expected-error {{static assertion failed due to requirement 'GH99873::A<int>().f<int>() != 0'}}
+                                           // expected-note at -1 {{expression evaluates to '0 != 0'}}
+}
+
+template<typename>
+class conditional {
+};
+
+// FIXME: The diagnostics here are produced twice.
+void foo(conditional<decltype((1),int>) {  // expected-note 2 {{to match this '('}} expected-error {{expected ')'}} expected-note 2{{to match this '<'}}
+} // expected-error {{expected function body after function declarator}} expected-error 2 {{expected '>'}} expected-error {{expected ')'}}

>From dcd985345b8a4938fd91bffd7fcfaca2b01be89b Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Mon, 29 Sep 2025 19:28:12 +0200
Subject: [PATCH 3/5] add tests

---
 clang/test/SemaCXX/decltype.cpp | 35 ++++++++++++++++++++++++---------
 1 file changed, 26 insertions(+), 9 deletions(-)

diff --git a/clang/test/SemaCXX/decltype.cpp b/clang/test/SemaCXX/decltype.cpp
index 7931c6ac45429..893090484fd54 100644
--- a/clang/test/SemaCXX/decltype.cpp
+++ b/clang/test/SemaCXX/decltype.cpp
@@ -157,12 +157,22 @@ struct A {
   }
 };
 
+
+
+// This shouldn't crash.
+static_assert(A<int>().f<int>() == 0, "");
+// The result should not be dependent.
+static_assert(A<int>().f<int>() != 0, ""); // expected-error {{static assertion failed due to requirement 'GH99873::A<int>().f<int>() != 0'}}
+                                           // expected-note at -1 {{expression evaluates to '0 != 0'}}
+}
+
+
 #if __cplusplus >= 201703L
 namespace GH160497 {
 
 template <class> struct S {
     template <class>
-    static inline auto mem =
+    inline static auto mem =
     [] { static_assert(false); // expected-error {{static assertion failed}} \
         // expected-note {{while substituting into a lambda expression here}}
         return 42;
@@ -170,7 +180,21 @@ template <class> struct S {
 };
 
 using T = decltype(S<void>::mem<void>);
- // expected-note at -1 {{in instantiation of static data member 'GH99873::GH160497::S<void>::mem<void>' requested here}}
+ // expected-note at -1 {{in instantiation of static data member 'GH160497::S<void>::mem<void>' requested here}}
+
+
+template <class> struct S2 {
+    template <class>
+    inline static auto* mem =
+    [] { static_assert(false); // expected-error {{static assertion failed}} \
+        // expected-note {{while substituting into a lambda expression here}}
+        return static_cast<int*>(nullptr);
+    }();
+};
+
+
+using T2 = decltype(S2<void>::mem<void>);
+//expected-note at -1 {{in instantiation of static data member 'GH160497::S2<void>::mem<void>' requested here}}
 
 namespace N1 {
 
@@ -188,13 +212,6 @@ T y = 42;
 }
 #endif
 
-// This shouldn't crash.
-static_assert(A<int>().f<int>() == 0, "");
-// The result should not be dependent.
-static_assert(A<int>().f<int>() != 0, ""); // expected-error {{static assertion failed due to requirement 'GH99873::A<int>().f<int>() != 0'}}
-                                           // expected-note at -1 {{expression evaluates to '0 != 0'}}
-}
-
 template<typename>
 class conditional {
 };

>From 8e56a5004269bd7d54a03d6451d2e35726e37d8e Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Mon, 29 Sep 2025 19:39:25 +0200
Subject: [PATCH 4/5] add test for GH56652

---
 clang/docs/ReleaseNotes.rst       |  2 +-
 clang/test/CodeGenCXX/gh56652.cpp | 28 ++++++++++++++++++++++++++++
 2 files changed, 29 insertions(+), 1 deletion(-)
 create mode 100644 clang/test/CodeGenCXX/gh56652.cpp

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index df277a13e9f23..5ce4adee66b21 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -379,7 +379,7 @@ Bug Fixes in This Version
 - Fixed an assertion when an improper use of the ``malloc`` attribute targeting
   a function without arguments caused us to try to access a non-existent argument.
   (#GH159080)
-- Fixed a failed assertion with empty filename arguments in ``__has_embed``. (#GH159898)
+- Fixed a failed assertion with empty filename arguments in ``__has_embed``. (#GH159898) (#GH56652)
 
 Bug Fixes to Compiler Builtins
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/test/CodeGenCXX/gh56652.cpp b/clang/test/CodeGenCXX/gh56652.cpp
new file mode 100644
index 0000000000000..0ccadd1493eed
--- /dev/null
+++ b/clang/test/CodeGenCXX/gh56652.cpp
@@ -0,0 +1,28 @@
+// RUN: %clang_cc1 -std=c++20 -triple x86_64-elf-gnu %s -emit-llvm -o - | FileCheck %s
+
+namespace GH56652{
+
+struct foo {};
+
+template <typename T> struct bar {
+    using type = T;
+
+    template <foo> inline static constexpr auto b = true;
+};
+
+template <typename T>
+concept C = requires(T a) { T::template b<foo{}>; };
+
+template <typename T> auto fn(T) {
+    if constexpr (!C<T>)
+        return foo{};
+    else
+        return T{};
+}
+
+auto a = decltype(fn(bar<int>{})){};
+
+}
+
+// CHECK: %"struct.GH56652::bar" = type { i8 }
+// CHECK: @_ZN7GH566521aE = global %"struct.GH56652::bar" undef

>From 401f93959aa1c96874499256e9be33a197f8a19a Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Mon, 29 Sep 2025 19:46:27 +0200
Subject: [PATCH 5/5] add test for GH1163191

---
 clang/docs/ReleaseNotes.rst       |  4 ++--
 clang/test/CodeGenCXX/gh56652.cpp | 13 +++++++++++++
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 5ce4adee66b21..0d8c781318128 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -379,7 +379,7 @@ Bug Fixes in This Version
 - Fixed an assertion when an improper use of the ``malloc`` attribute targeting
   a function without arguments caused us to try to access a non-existent argument.
   (#GH159080)
-- Fixed a failed assertion with empty filename arguments in ``__has_embed``. (#GH159898) (#GH56652)
+- Fixed a failed assertion with empty filename arguments in ``__has_embed``. (#GH159898)
 
 Bug Fixes to Compiler Builtins
 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -433,7 +433,7 @@ Bug Fixes to C++ Support
   object type. (#GH151531)
 - Suppress ``-Wdouble-promotion`` when explicitly asked for with C++ list initialization (#GH33409).
 - Fix the result of `__builtin_is_implicit_lifetime` for types with a user-provided constructor. (#GH160610)
-- Correctly deduced return types in ``decltype`` expressions. (#GH160497)
+- Correctly deduced return types in ``decltype`` expressions. (#GH160497) (#GH56652) (#GH116319)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/test/CodeGenCXX/gh56652.cpp b/clang/test/CodeGenCXX/gh56652.cpp
index 0ccadd1493eed..06a496e320bfc 100644
--- a/clang/test/CodeGenCXX/gh56652.cpp
+++ b/clang/test/CodeGenCXX/gh56652.cpp
@@ -22,7 +22,20 @@ template <typename T> auto fn(T) {
 
 auto a = decltype(fn(bar<int>{})){};
 
+}
+
+namespace GH116319 {
+
+template <int = 0> struct a {
+template <class> static constexpr auto b = 2;
+template <class> static void c() noexcept(noexcept(b<int>)) {}
+};
+
+void test() { a<>::c<int>(); }
+
+
 }
 
 // CHECK: %"struct.GH56652::bar" = type { i8 }
+// CHECK: $_ZN8GH1163191aILi0EE1cIiEEvv = comdat any
 // CHECK: @_ZN7GH566521aE = global %"struct.GH56652::bar" undef



More information about the cfe-commits mailing list