[clang] [clang][Interp] Fix diagnosing non-const variables pre-C++11 (PR #76718)

Timm Baeder via cfe-commits cfe-commits at lists.llvm.org
Mon Jan 15 02:39:58 PST 2024


https://github.com/tbaederr updated https://github.com/llvm/llvm-project/pull/76718

>From aa6691d530024a57be78b19e9a682b4676a235d6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbaeder at redhat.com>
Date: Sat, 30 Dec 2023 20:46:13 +0100
Subject: [PATCH] [clang][Interp] Fix diagnosing non-const variables pre-C++11

In CheckConstant(), consider that in C++98 const variables may not be
read at all, and diagnose that accordingly.
---
 clang/lib/AST/Interp/Interp.cpp | 42 ++++++++++++++++++++++++++-------
 clang/test/AST/Interp/cxx11.cpp | 24 +++++++++++++++++++
 clang/test/AST/Interp/cxx98.cpp | 36 ++++++++++++++++++++++++++++
 3 files changed, 93 insertions(+), 9 deletions(-)
 create mode 100644 clang/test/AST/Interp/cxx11.cpp
 create mode 100644 clang/test/AST/Interp/cxx98.cpp

diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp
index b95a52199846fa0..bdb86322df663e9 100644
--- a/clang/lib/AST/Interp/Interp.cpp
+++ b/clang/lib/AST/Interp/Interp.cpp
@@ -59,12 +59,16 @@ static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,
     return;
 
   const SourceInfo &Loc = S.Current->getSource(OpPC);
-  S.FFDiag(Loc,
-           VD->getType()->isIntegralOrEnumerationType()
-               ? diag::note_constexpr_ltor_non_const_int
-               : diag::note_constexpr_ltor_non_constexpr,
-           1)
-      << VD;
+
+  if (VD->getType()->isIntegralOrEnumerationType())
+    S.FFDiag(Loc, diag::note_constexpr_ltor_non_const_int, 1) << VD;
+  else
+    S.FFDiag(Loc,
+             S.getLangOpts().CPlusPlus11
+                 ? diag::note_constexpr_ltor_non_constexpr
+                 : diag::note_constexpr_ltor_non_integral,
+             1)
+        << VD << VD->getType();
   S.Note(VD->getLocation(), diag::note_declared_at);
 }
 
@@ -231,12 +235,32 @@ bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
 
 bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
   assert(Desc);
+
+  auto IsConstType = [&S](const VarDecl *VD) -> bool {
+    if (VD->isConstexpr())
+      return true;
+
+    if (S.getLangOpts().CPlusPlus && !S.getLangOpts().CPlusPlus11)
+      return false;
+
+    QualType T = VD->getType();
+    if (T.isConstQualified())
+      return true;
+
+    if (const auto *RT = T->getAs<ReferenceType>())
+      return RT->getPointeeType().isConstQualified();
+
+    if (const auto *PT = T->getAs<PointerType>())
+      return PT->getPointeeType().isConstQualified();
+
+    return false;
+  };
+
   if (const auto *D = Desc->asValueDecl()) {
     if (const auto *VD = dyn_cast<VarDecl>(D);
-        VD && VD->hasGlobalStorage() &&
-        !(VD->isConstexpr() || VD->getType().isConstQualified())) {
+        VD && VD->hasGlobalStorage() && !IsConstType(VD)) {
       diagnoseNonConstVariable(S, OpPC, VD);
-      return false;
+      return S.inConstantContext();
     }
   }
 
diff --git a/clang/test/AST/Interp/cxx11.cpp b/clang/test/AST/Interp/cxx11.cpp
new file mode 100644
index 000000000000000..81e293fec175020
--- /dev/null
+++ b/clang/test/AST/Interp/cxx11.cpp
@@ -0,0 +1,24 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=both,expected -std=c++11 %s
+// RUN: %clang_cc1 -verify=both,ref -std=c++11 %s
+
+// expected-no-diagnostics
+
+namespace IntOrEnum {
+  const int k = 0;
+  const int &p = k;
+  template<int n> struct S {};
+  S<p> s;
+}
+
+const int cval = 2;
+template <int> struct C{};
+template struct C<cval>;
+
+
+/// FIXME: This example does not get properly diagnosed in the new interpreter.
+extern const int recurse1;
+const int recurse2 = recurse1; // ref-note {{here}}
+const int recurse1 = 1;
+int array1[recurse1];
+int array2[recurse2]; // ref-warning 2{{variable length array}} \
+                      // ref-note {{initializer of 'recurse2' is not a constant expression}}
diff --git a/clang/test/AST/Interp/cxx98.cpp b/clang/test/AST/Interp/cxx98.cpp
new file mode 100644
index 000000000000000..bc96723c2287da4
--- /dev/null
+++ b/clang/test/AST/Interp/cxx98.cpp
@@ -0,0 +1,36 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=both,expected -std=c++98 %s
+// RUN: %clang_cc1 -verify=both,ref -std=c++98 %s
+
+
+
+namespace IntOrEnum {
+  const int k = 0;
+  const int &p = k; // both-note {{declared here}}
+  template<int n> struct S {};
+  S<p> s; // both-error {{not an integral constant expression}} \
+          // both-note {{read of variable 'p' of non-integral, non-enumeration type 'const int &'}}
+}
+
+const int cval = 2;
+template <int> struct C{};
+template struct C<cval>;
+
+
+/// FIXME: This example does not get properly diagnosed in the new interpreter.
+extern const int recurse1;
+const int recurse2 = recurse1; // ref-note {{here}}
+const int recurse1 = 1;
+int array1[recurse1];
+int array2[recurse2]; // ref-warning 2{{variable length array}} \
+                      // ref-note {{initializer of 'recurse2' is not a constant expression}} \
+                      // expected-warning {{variable length array}} \
+                      // expected-error {{variable length array}}
+
+int NCI; // expected-note {{declared here}} \
+         // ref-note {{declared here}}
+int NCIA[NCI]; // expected-warning {{variable length array}} \
+               // expected-error {{variable length array}} \\
+               // expected-note {{read of non-const variable 'NCI'}} \
+               // ref-warning {{variable length array}} \
+               // ref-error {{variable length array}} \\
+               // ref-note {{read of non-const variable 'NCI'}}



More information about the cfe-commits mailing list