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

>From b9b404c9494cb9b4ee37facf6fe582a9ace1fde0 Mon Sep 17 00:00:00 2001
From: Gauravpawar101 <[email protected]>
Date: Tue, 29 Sep 2026 17:25:41 +0530
Subject: [PATCH] Add regression tests for crashes caused by `decltype(&x)`
 where `x` is a static data member of a class template.

`computeDependence(UnaryOperator*)` used to set only `ExprDependence::Value` for
`&x` when `x` is a templated entity with static storage duration
([temp.dep.constexpr]p5), without the `Instantiation` bit. The resulting
DecltypeType was flagged dependent but not instantiation-dependent, so
`SubstType`/`VisitFieldDecl` skipped substituting it and the dependent type
leaked into the instantiation (assertion in `getTypeInfoImpl` during record
layout; a crash in `ConstantEmitter` for the CodeGen case).

This was fixed as a side effect of #208012 (aaa4ebd2a), which changed the
bit to `ValueInstantiation`, but no test covered these cases. No source
changes are needed here.

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

Validated by reverting the one-line change from #208012: the Sema test asserts
in `getTypeInfoImpl` and the CodeGen test asserts in 
`ConstantEmitter::tryEmitPrivate`;
both pass on unmodified `main`. The Sema test only fails in
assertion-enabled builds.

### Verification
Checked on Compiler Explorer: the assertion reproduces from clang 12
through trunk (assertions enabled). The AST differs between 12 and 13+
(the expression gains instantiation-dependence in 13+), but the 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

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to