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?= <tbae...@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'}} _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits