[clang] [Clang] Fix misleading diagnostic for pointer const type static data member (PR #223596)

Alexsander Borges Damaceno via cfe-commits cfe-commits at lists.llvm.org
Mon Sep 14 21:12:26 PDT 2026


https://github.com/AlexsanderDamaceno created https://github.com/llvm/llvm-project/pull/223596

For a static data member of pointer-to-const type (e.g. 'const char *'), Clang emits:

` error: non-const static data member must be initialized out of line
`

This message is misleading. The most appropriate diagnostic here would be:

`error: in-class initializer for static data member of type '....' requires 'constexpr' specifier`

GCC reports similar to the above message sugesting add 'constexpr'

The constexpr expression diagnostic was never reached because the preceding
check only verified `!DclT.isConstQualified(),` which excludes this pointer
case.

For `const char *`, the const qualifier binds to the pointee (char), not
to the pointer itself. Therefore, the pointer's own type is not
const-qualified, causing the "non-const" branch to fire first before the
constexpr-related diagnostics can be reached.

This patch adds  check to const case, so a pointer whose pointee is const no longer takes the `non-const`  diag branch , letting it fall through to the existing constexpr-related diagnostics instead.

>From 528136310cc83c9a9519d851e5d389cc1624e566 Mon Sep 17 00:00:00 2001
From: AlexsanderDamaceno <aemgbo at gmail.com>
Date: Tue, 15 Sep 2026 00:53:07 -0300
Subject: [PATCH] [Clang] Fix misleading diagnostic for pointer-to-const static
 data members

For a static data member of pointer-to-const type (e.g. 'const char *'),
Clang emits:

    error: non-const static data member must be initialized out of line

This message is misleading. The most appropriate diagnostic here would be:

error: in-class initializer for static data member of type '....'
       requires 'constexpr' specifier

GCC reports similar to the above message sugesting add 'constexpr'

the diagnostic 'constexpr' expression diagnostig was never reached,
the preceding check only verified '!DclT.isConstQualified()', which
excludes exactly this pointer case. For 'const char *', the const
binds to the pointee (char), not to the pointer itself, so the
pointer's own type is not const-qualified, and the "non-const" branch
fires first before the constexpr-related diagnostics ever get a
chance to run.

This patch narrows that check so a pointer whose pointee is const no
longer takes the "non-const" branch, letting it fall through to the
existing (and already correct) constexpr-related diagnostics instead.
---
 clang/lib/Sema/SemaDecl.cpp                                | 4 +++-
 clang/test/CXX/class/class.static/class.static.data/p3.cpp | 3 +++
 2 files changed, 6 insertions(+), 1 deletion(-)

diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index 7e1b23c971a9c..140bb22f2a4e2 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -14333,7 +14333,9 @@ void Sema::AddInitializerToDecl(Decl *RealDecl, Expr *Init, bool DirectInit) {
     } else if (VDecl->isConstexpr()) {
 
     // Require constness.
-    } else if (!DclT.isConstQualified()) {
+    } else if (!DclT.isConstQualified() &&
+               !(DclT->isPointerType() &&
+                 DclT->getPointeeType().isConstQualified())) {
       Diag(VDecl->getLocation(), diag::err_in_class_initializer_non_const)
         << Init->getSourceRange();
       VDecl->setInvalidDecl();
diff --git a/clang/test/CXX/class/class.static/class.static.data/p3.cpp b/clang/test/CXX/class/class.static/class.static.data/p3.cpp
index 5640bc30ad4c7..81844d90d6516 100644
--- a/clang/test/CXX/class/class.static/class.static.data/p3.cpp
+++ b/clang/test/CXX/class/class.static/class.static.data/p3.cpp
@@ -18,6 +18,9 @@ struct S {
   static char *const g = 0; // expected-error {{requires 'constexpr' specifier}}
   static const NonLit h = NonLit(); // expected-error {{must be initialized out of line}}
 
+  static const char *aaa = "aaa"; // expected-error {{requires 'constexpr' specifier}}
+  static int *i2 = 0; // expected-error {{non-const static data member must be initialized out of line}}
+
   static inline int i; // expected-note {{previous}} expected-warning 0-1{{extension}}
   static inline int j; // expected-note {{previous}} expected-warning 0-1{{extension}}
   static constexpr int k = 0;



More information about the cfe-commits mailing list