https://github.com/GauravPawar101 updated https://github.com/llvm/llvm-project/pull/227288
>From a9f4a00de9d095b1c6fa3e5cd2b0a9459629e65b 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 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 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
