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

via cfe-commits cfe-commits at lists.llvm.org
Thu Jan 18 06:15:09 PST 2024


Author: Timm Baeder
Date: 2024-01-18T15:15:05+01:00
New Revision: 30d458626d4fb7adf94b195e98de240b491c86c9

URL: https://github.com/llvm/llvm-project/commit/30d458626d4fb7adf94b195e98de240b491c86c9
DIFF: https://github.com/llvm/llvm-project/commit/30d458626d4fb7adf94b195e98de240b491c86c9.diff

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

In CheckConstant(), consider that in C++98 const variables may not be read at all, and diagnose that accordingly.

Added: 
    clang/test/AST/Interp/cxx11.cpp
    clang/test/AST/Interp/cxx98.cpp

Modified: 
    clang/lib/AST/Interp/Interp.cpp

Removed: 
    


################################################################################
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..79f93c8d78f16ee
--- /dev/null
+++ b/clang/test/AST/Interp/cxx98.cpp
@@ -0,0 +1,32 @@
+// 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; // both-note {{declared here}}
+int NCIA[NCI]; // both-warning {{variable length array}} \
+               // both-error {{variable length array}} \\
+               // both-note {{read of non-const variable 'NCI'}}


        


More information about the cfe-commits mailing list