Lnkqwq wrote:
This PR fixes #88603, an inconsistency in Clang's diagnostic output when
handling `const volatile` integer static data member initializers in C++98 mode.
## Problem
Consider the following code (C++98):
```cpp
const int a = 1;
const volatile int b = 1;
struct S {
static const int ay = a; // OK
static const int by = b; // error, but no note
int az : a; // OK
int bz : b; // error + note
};
```
Current Clang output:
```
<source>:5:25: error: in-class initializer for static data member is not a
constant expression
static const int by = b;
^
<source>:7:12: error: expression is not an integral constant expression
int bz : b;
^
<source>:7:12: note: read of volatile-qualified type 'const volatile int' is
not allowed in a constant expression
```
The inconsistency: Both contexts (static member initializer and bit-field
width) require an integral constant expression in C++98, but only the bit-field
case emits the helpful note explaining why it's not constant (volatile read).
The static member case just says "not a constant expression" without
explanation.
Root Cause Analysis
In SemaDecl.cpp, the code that handles static data member initializers has a
branch for integral/enumeration types:
```cpp
} else if (DclT->isIntegralOrEnumerationType()) {
if (getLangOpts().CPlusPlus11 && DclT.isVolatileQualified())
Diag(VDecl->getLocation(), diag::err_in_class_initializer_volatile);
// No constant expression check in C++98 mode!
}
```
For C++98, this branch does no constant expression checking at all—it simply
accepts the initializer without verification. This is why no diagnostic (error
or note) is produced for the volatile case in C++98.
In contrast, the bit-field handling code (elsewhere) calls
EvaluateAsConstantExpr(), which performs full constant expression evaluation
and captures detailed diagnostics (like the volatile read note).
Solution
This PR adds constant expression checking to the integral/enumeration branch
for all language modes (not just C++11+):
```cpp
} else if (DclT->isIntegralOrEnumerationType()) {
if (getLangOpts().CPlusPlus11 && DclT.isVolatileQualified())
Diag(VDecl->getLocation(), diag::err_in_class_initializer_volatile);
// NEW: Check if it's really a constant expression (for all language modes)
if (!Init->isValueDependent()) {
Expr::EvalResult EvalResult;
if (!Init->EvaluateAsConstantExpr(EvalResult, Context)) {
Diag(Init->getExprLoc(), diag::err_in_class_initializer_non_constant)
<< Init->getSourceRange();
VDecl->setInvalidDecl();
// Propagate any detailed notes from evaluation (e.g., volatile read)
if (EvalResult.Diag) {
Diag(EvalResult.Diag->first, EvalResult.Diag->second);
}
}
}
}
```
This makes the static member initializer path:
1. Actually verify that the initializer is a valid constant expression
2. Capture and report the same detailed diagnostics that other contexts (like
bit-fields) already emit
https://github.com/llvm/llvm-project/pull/185021
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits