[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