[clang] Fix C23 constexpr crashes (#112708)
authorMariya Podchishchaeva <mariya.podchishchaeva@intel.com>
Fri, 18 Oct 2024 08:18:34 +0000 (10:18 +0200)
committerTobias Hieta <tobias@hieta.se>
Fri, 15 Nov 2024 08:26:14 +0000 (09:26 +0100)
Before using a constexpr variable that is not properly initialized check
that it is valid.

Fixes https://github.com/llvm/llvm-project/issues/109095
Fixes https://github.com/llvm/llvm-project/issues/112516

clang/lib/AST/Decl.cpp
clang/test/Sema/constexpr.c

index 490c4a2fc525cd6e81537e98a862ee5b998409a6..bc7cce0bcd7fc27afafd80f74feb5872b4595aed 100644 (file)
@@ -2503,7 +2503,8 @@ bool VarDecl::isUsableInConstantExpressions(const ASTContext &Context) const {
   if (!DefVD->mightBeUsableInConstantExpressions(Context))
     return false;
   //   ... and its initializer is a constant initializer.
-  if (Context.getLangOpts().CPlusPlus && !DefVD->hasConstantInitialization())
+  if ((Context.getLangOpts().CPlusPlus || getLangOpts().C23) &&
+      !DefVD->hasConstantInitialization())
     return false;
   // C++98 [expr.const]p1:
   //   An integral constant-expression can involve only [...] const variables
@@ -2610,8 +2611,11 @@ bool VarDecl::hasICEInitializer(const ASTContext &Context) const {
 }
 
 bool VarDecl::hasConstantInitialization() const {
-  // In C, all globals (and only globals) have constant initialization.
-  if (hasGlobalStorage() && !getASTContext().getLangOpts().CPlusPlus)
+  // In C, all globals and constexpr variables should have constant
+  // initialization. For constexpr variables in C check that initializer is a
+  // constant initializer because they can be used in constant expressions.
+  if (hasGlobalStorage() && !getASTContext().getLangOpts().CPlusPlus &&
+      !isConstexpr())
     return true;
 
   // In C++, it depends on whether the evaluation at the point of definition
index a874fd64808404e92f3ae3791d86c466f6509553..ad2c2ba98a1e3fd03b4cbddc408ca3261cbebcd0 100644 (file)
@@ -364,3 +364,20 @@ void constexprif() {
 void constevalif() {
   if consteval (300) {} //expected-error {{expected '(' after 'if'}}
 }
+
+struct S11 {
+  int len;
+};
+void ghissue112516() {
+  struct S11 *s11 = 0;
+  constexpr int num = s11->len; // expected-error {{constexpr variable 'num' must be initialized by a constant expression}}
+  void *Arr[num];
+}
+
+void ghissue109095() {
+  constexpr char c[] = { 'a' };
+  constexpr int i = c[1]; // expected-error {{constexpr variable 'i' must be initialized by a constant expression}}\
+                          // expected-note {{declared here}}
+  _Static_assert(i == c[0]); // expected-error {{static assertion expression is not an integral constant expression}}\
+                             // expected-note {{initializer of 'i' is not a constant expression}}
+}