[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