[clang] [clang] Add regression tests for decltype(&static data member) in class templates (PR #227288)

Gaurav Pawar via cfe-commits cfe-commits at lists.llvm.org
Wed Sep 30 22:57:32 PDT 2026


https://github.com/GauravPawar101 updated https://github.com/llvm/llvm-project/pull/227288

>From a9f4a00de9d095b1c6fa3e5cd2b0a9459629e65b Mon Sep 17 00:00:00 2001
From: Gauravpawar101 <Gauravpawar2522 at gmail.com>
Date: Tue, 29 Sep 2026 17:25:41 +0530
Subject: [PATCH] [clang] Add regression tests for decltype(&static data
 member) in class templates

The bug: computeDependence() set only Value (not Instantiation) for
&static_data_member per [temp.dep.constexpr]p5. The dependent decltype()
type leaked into instantiations, asserting in getTypeInfoImpl (Sema) and
ConstantEmitter::tryEmitPrivate (CodeGen).

Fixed as a side effect of #208012 (aaa4ebd2a); no source changes needed.

### Tests:
- clang/test/SemaCXX/GH175934.cpp: field of type decltype(&static member)
  (plain, constexpr, array, alias/typedef, nested/derived layout,
  function-local static).
- clang/test/CodeGenCXX/GH110041.cpp: static member initializer + auto x = a<int>::c;
  and function-local decltype(&e).

Verified: asserts on clang 12+ (assertions enabled); passes on fixed main.
AST differs in 13+ (gains Instantiation bit) but failure is the same.

Fixes #175934
Fixes #110041
---
 clang/test/CodeGenCXX/GH110041.cpp | 26 ++++++++
 clang/test/SemaCXX/GH175934.cpp    | 96 ++++++++++++++++++++++++++++++
 2 files changed, 122 insertions(+)
 create mode 100644 clang/test/CodeGenCXX/GH110041.cpp
 create mode 100644 clang/test/SemaCXX/GH175934.cpp

diff --git a/clang/test/CodeGenCXX/GH110041.cpp b/clang/test/CodeGenCXX/GH110041.cpp
new file mode 100644
index 0000000000000..6f8a02bb5e575
--- /dev/null
+++ b/clang/test/CodeGenCXX/GH110041.cpp
@@ -0,0 +1,26 @@
+// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s | FileCheck %s
+
+// Regression test for https://github.com/llvm/llvm-project/issues/110041
+// (root cause shared with https://github.com/llvm/llvm-project/issues/175934:
+// `&static_data_member` was value-dependent but not instantiation-dependent, so
+// decltype(&b) kept its uninstantiated, dependent-flagged type in a<int>).
+// This used to crash CodeGen in ConstantEmitter::tryEmitPrivate.
+
+template <typename> struct a {
+  static char const b{};
+  static decltype(&b) constexpr c{&b};
+};
+
+// CHECK: @x = {{.*}}global ptr @_ZN1aIiE1bE
+auto x = a<int>::c;
+
+// Local variant: the variable's type comes from decltype(&static_local).
+template <class T> int get() {
+  static const int e = 42;
+  decltype(&e) p = &e;
+  return *p;
+}
+
+// CHECK-LABEL: define {{.*}}i32 @_Z3getIiEiv()
+// CHECK: ret i32
+int use() { return get<int>(); }
diff --git a/clang/test/SemaCXX/GH175934.cpp b/clang/test/SemaCXX/GH175934.cpp
new file mode 100644
index 0000000000000..2bb077e85158d
--- /dev/null
+++ b/clang/test/SemaCXX/GH175934.cpp
@@ -0,0 +1,96 @@
+// RUN: %clang_cc1 -std=c++11 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++17 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
+// expected-no-diagnostics
+
+// Regression tests for https://github.com/llvm/llvm-project/issues/175934
+// (and the same root cause as https://github.com/llvm/llvm-project/issues/110041).
+//
+// [temp.dep.constexpr]p5 makes `&x` value-dependent when `x` is a templated
+// entity with static storage duration, even if `x` itself is not dependent.
+// computeDependence(UnaryOperator*) used to set only the Value bit, leaving the
+// expression not instantiation-dependent. decltype(&x) was then flagged as a
+// dependent type but was never re-substituted on instantiation, so the
+// uninstantiated type leaked into the specialization and asserted with
+// "should not see dependent types here" in ASTContext::getTypeInfoImpl.
+
+template <class T, class U> struct is_same { static const bool value = false; };
+template <class T> struct is_same<T, T> { static const bool value = true; };
+
+namespace field_of_class_template {
+// The original reproducer.
+template <class T> struct Y {
+  static const int e = 1;
+  decltype(&e) g;
+};
+
+Y<int> y; // Crashed here: constructor call checks compute the record layout.
+static_assert(sizeof(Y<int>) == sizeof(const int *), "");
+static_assert(alignof(Y<int>) == alignof(const int *), "");
+// The field type must be re-evaluated for each specialization.
+static_assert(is_same<decltype(Y<int>().g), const int *>::value, "");
+static_assert(is_same<decltype(Y<char>().g), const int *>::value, "");
+static_assert(sizeof(Y<char>) == sizeof(Y<int>), "");
+} // namespace field_of_class_template
+
+namespace constexpr_static_member {
+template <class T> struct Y {
+  static constexpr int e = 1;
+  decltype(&e) g;
+};
+static_assert(sizeof(Y<int>) == sizeof(const int *), "");
+static_assert(is_same<decltype(Y<int>().g), const int *>::value, "");
+} // namespace constexpr_static_member
+
+namespace array_static_member {
+// &arr has type `const int (*)[2]`.
+template <class T> struct Y {
+  static constexpr int arr[2] = {1, 2};
+  decltype(&arr) g;
+};
+static_assert(sizeof(Y<int>) == sizeof(void *), "");
+static_assert(is_same<decltype(Y<int>().g), const int (*)[2]>::value, "");
+} // namespace array_static_member
+
+namespace via_alias_and_multiple_members {
+template <class T> struct Y {
+  static const int e = 1;
+  using P = decltype(&e);
+  typedef decltype(&e) Q;
+  P a;
+  Q b;
+  decltype(&e) c;
+};
+static_assert(sizeof(Y<int>) == 3 * sizeof(const int *), "");
+static_assert(is_same<Y<int>::P, const int *>::value, "");
+static_assert(is_same<Y<int>::Q, const int *>::value, "");
+} // namespace via_alias_and_multiple_members
+
+namespace nested_layout {
+// The bad field type must not poison records that contain the specialization.
+template <class T> struct Y {
+  static const int e = 1;
+  decltype(&e) g;
+};
+struct Outer {
+  char c;
+  Y<int> y;
+};
+struct Derived : Y<long> {
+  int i;
+};
+static_assert(sizeof(Outer) >= sizeof(char) + sizeof(const int *), "");
+static_assert(sizeof(Derived) >= sizeof(const int *) + sizeof(int), "");
+} // namespace nested_layout
+
+namespace function_local_static {
+// Same rule applies to a static local of a function template.
+template <class T> int f() {
+  static const int e = 1;
+  decltype(&e) p = &e;
+  static_assert(is_same<decltype(p), const int *>::value, "");
+  static_assert(sizeof(p) == sizeof(const int *), "");
+  return *p;
+}
+int use = f<int>() + f<char>();
+} // namespace function_local_static



More information about the cfe-commits mailing list