https://github.com/GauravPawar101 created https://github.com/llvm/llvm-project/pull/227288
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: - SemaTemplate/GH175934.cpp: field of type `decltype(&static member)` (plain, constexpr, array, alias/typedef, nested/derived layout, and a function-local static), forcing record layout. - CodeGenCXX/GH110041.cpp: static member initializer plus `auto x = a<int>::c;`. Validated by reverting the one-line change from #208012: the Sema test asserts in `getTypeInfoImpl` and the CodeGen test asserts in `evaluateValueImpl`; both pass on unmodified `main`. The Sema test only fails in assertion-enabled builds. Fixes #175934 Fixes #110041 >From 7e384f73f9e4c152835f8d04883e7eb1e3a27471 Mon Sep 17 00:00:00 2001 From: Gauravpawar101 <[email protected]> Date: Tue, 29 Sep 2026 17:25:41 +0530 Subject: [PATCH] [clang] Add regression tests for decltype(&static data member) in class templates --- ...ecltype-static-data-member-initializer.cpp | 26 +++++ .../SemaCXX/decltype-static-data-member.cpp | 96 +++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 clang/test/CodeGenCXX/decltype-static-data-member-initializer.cpp create mode 100644 clang/test/SemaCXX/decltype-static-data-member.cpp diff --git a/clang/test/CodeGenCXX/decltype-static-data-member-initializer.cpp b/clang/test/CodeGenCXX/decltype-static-data-member-initializer.cpp new file mode 100644 index 0000000000000..6f8a02bb5e575 --- /dev/null +++ b/clang/test/CodeGenCXX/decltype-static-data-member-initializer.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/decltype-static-data-member.cpp b/clang/test/SemaCXX/decltype-static-data-member.cpp new file mode 100644 index 0000000000000..2bb077e85158d --- /dev/null +++ b/clang/test/SemaCXX/decltype-static-data-member.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
