[clang] [Clang] Allow explicit member specialization to differ from template declaration wrt constexpr (PR #145272)
Vikram Hegde via cfe-commits
cfe-commits at lists.llvm.org
Sun Jun 22 23:00:35 PDT 2025
https://github.com/vikramRH created https://github.com/llvm/llvm-project/pull/145272
This attempts to fix https://github.com/llvm/llvm-project/issues/26078. However I have couple of fundamental questions with the 7.1.5 consexpr note
"[ Note: An explicit specialization can differ from the template declaration with respect to the constexpr specifier. — end note ]"
1. Does it also apply to member specializations which are not function templates themselves ? (as in the example https://godbolt.org/z/c4bYY8rxb)
2. if yes, then should it also apply to special member functions ? (constructors, destructors)
>From f525e34feaf519b1951733034dd71893aa79ae53 Mon Sep 17 00:00:00 2001
From: vikhegde <vikram.hegde at amd.com>
Date: Mon, 23 Jun 2025 10:39:03 +0530
Subject: [PATCH] [Clang] Allow explicit member specialization to differ from
template declaration wrt constexpr
---
clang/lib/Sema/SemaDecl.cpp | 17 +++++++++++++++++
.../CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp | 6 ++++++
.../CXX/temp/temp.spec/temp.expl.spec/p12.cpp | 13 ++++---------
3 files changed, 27 insertions(+), 9 deletions(-)
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 5cffd82e3372e..2ceb277eedcf5 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -12163,6 +12163,23 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
}
}
+ // C++11 [dcl.constexpr]p1: An explicit specialization of a constexpr
+ // function can differ from the template declaration with respect to
+ // the constexpr specifier.
+ if (IsMemberSpecialization) {
+ FunctionDecl *InstantiationFunction =
+ OldDecl ? OldDecl->getAsFunction() : nullptr;
+ if (InstantiationFunction &&
+ InstantiationFunction->getTemplateSpecializationKind() ==
+ TSK_ImplicitInstantiation &&
+ (NewFD->getTemplateSpecializationKind() == TSK_ExplicitSpecialization ||
+ NewFD->getTemplateSpecializationKind() == TSK_Undeclared)) {
+ if (InstantiationFunction->getConstexprKind() !=
+ NewFD->getConstexprKind())
+ InstantiationFunction->setConstexprKind(NewFD->getConstexprKind());
+ }
+ }
+
if (Redeclaration) {
// NewFD and OldDecl represent declarations that need to be
// merged.
diff --git a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
index 752451f3d9749..225adb2228a03 100644
--- a/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
+++ b/clang/test/CXX/dcl.dcl/dcl.spec/dcl.constexpr/p1.cpp
@@ -94,7 +94,13 @@ struct S {
#endif
};
+template<typename T>
+struct P {
+ constexpr T h() const { return 1;}
+};
+
// explicit specialization can differ in constepxr
+template <> int P<int>::h() const { return 0; }
template <> notlit ft(notlit nl) { return nl; }
template <> char ft(char c) { return c; } // expected-note {{previous}}
template <> constexpr char ft(char nl); // expected-error {{constexpr declaration of 'ft<char>' follows non-constexpr declaration}}
diff --git a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p12.cpp b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p12.cpp
index 9717fbf419b0a..af2b17ea2c089 100644
--- a/clang/test/CXX/temp/temp.spec/temp.expl.spec/p12.cpp
+++ b/clang/test/CXX/temp/temp.spec/temp.expl.spec/p12.cpp
@@ -1,6 +1,5 @@
// RUN: %clang_cc1 -fsyntax-only -std=c++11 -verify=expected,cxx11 %s
// RUN: %clang_cc1 -fsyntax-only -std=c++14 -verify=expected,since-cxx14 %s
-
struct A {
template<typename T>
void f0();
@@ -32,11 +31,9 @@ constexpr void A::f1<long>(); // since-cxx14-error {{no function template matche
// instantiated specialization of that template.
template<typename T>
struct B { // #defined-here
- void g0(); // since-cxx14-note {{previous declaration is here}}
- // cxx11-note at -1 {{member declaration does not match because it is not const qualified}}
+ void g0(); // cxx11-note {{member declaration does not match because it is not const qualified}}
void g1() const; // since-cxx14-note {{member declaration does not match because it is const qualified}}
- // cxx11-note at -1 {{previous declaration is here}}
template<typename U>
void h0(); // since-cxx14-note {{previous declaration is here}}
@@ -46,15 +43,13 @@ struct B { // #defined-here
};
template<>
-constexpr void B<short>::g0(); // since-cxx14-error {{constexpr declaration of 'g0' follows non-constexpr declaration}}
- // cxx11-error at -1 {{out-of-line declaration of 'g0' does not match any declaration in 'B<short>'}}
- // cxx11-warning at -2 {{'constexpr' non-static member function will not be implicitly 'const' in C++14; add 'const'}}
+constexpr void B<short>::g0(); // cxx11-error {{out-of-line declaration of 'g0' does not match any declaration in 'B<short>'}}
+ // cxx11-warning at -1 {{'constexpr' non-static member function will not be implicitly 'const' in C++14; add 'const'}}
// expected-note@#defined-here {{defined here}}
template<>
constexpr void B<short>::g1(); // since-cxx14-error {{out-of-line declaration of 'g1' does not match any declaration in 'B<short>'}}
- // cxx11-error at -1 {{constexpr declaration of 'g1' follows non-constexpr declaration}}
- // cxx11-warning at -2 {{'constexpr' non-static member function will not be implicitly 'const' in C++14; add 'const'}}
+ // cxx11-warning at -1 {{'constexpr' non-static member function will not be implicitly 'const' in C++14; add 'const'}}
// expected-note@#defined-here {{defined here}}
template<>
More information about the cfe-commits
mailing list