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.he...@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@-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@-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@-1 {{out-of-line declaration of 'g0' does not match any declaration in 'B<short>'}} - // cxx11-warning@-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@-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@-1 {{constexpr declaration of 'g1' follows non-constexpr declaration}} - // cxx11-warning@-2 {{'constexpr' non-static member function will not be implicitly 'const' in C++14; add 'const'}} + // cxx11-warning@-1 {{'constexpr' non-static member function will not be implicitly 'const' in C++14; add 'const'}} // expected-note@#defined-here {{defined here}} template<> _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits