[clang] [Sema] Improve diagnostic for volatile static data member initializer… (PR #185021)

via cfe-commits cfe-commits at lists.llvm.org
Fri Mar 6 07:28:30 PST 2026


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


More information about the cfe-commits mailing list