Skip to content

Commit

Permalink
[clang][Interp] Fix diagnosing non-const variables pre-C++11 (#76718)
Browse files Browse the repository at this point in the history
In CheckConstant(), consider that in C++98 const variables may not be read at all, and diagnose that accordingly.
  • Loading branch information
tbaederr committed Jan 18, 2024
1 parent 57f6a3f commit 30d4586
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 9 deletions.
42 changes: 33 additions & 9 deletions clang/lib/AST/Interp/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}

Expand Down Expand Up @@ -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();
}
}

Expand Down
24 changes: 24 additions & 0 deletions clang/test/AST/Interp/cxx11.cpp
Original file line number Diff line number Diff line change
@@ -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}}
32 changes: 32 additions & 0 deletions clang/test/AST/Interp/cxx98.cpp
Original file line number Diff line number Diff line change
@@ -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'}}

0 comments on commit 30d4586

Please sign in to comment.