Skip to content

Commit 30d4586

Browse files
authored
[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.
1 parent 57f6a3f commit 30d4586

File tree

3 files changed

+89
-9
lines changed

3 files changed

+89
-9
lines changed

clang/lib/AST/Interp/Interp.cpp

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -59,12 +59,16 @@ static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,
5959
return;
6060

6161
const SourceInfo &Loc = S.Current->getSource(OpPC);
62-
S.FFDiag(Loc,
63-
VD->getType()->isIntegralOrEnumerationType()
64-
? diag::note_constexpr_ltor_non_const_int
65-
: diag::note_constexpr_ltor_non_constexpr,
66-
1)
67-
<< VD;
62+
63+
if (VD->getType()->isIntegralOrEnumerationType())
64+
S.FFDiag(Loc, diag::note_constexpr_ltor_non_const_int, 1) << VD;
65+
else
66+
S.FFDiag(Loc,
67+
S.getLangOpts().CPlusPlus11
68+
? diag::note_constexpr_ltor_non_constexpr
69+
: diag::note_constexpr_ltor_non_integral,
70+
1)
71+
<< VD << VD->getType();
6872
S.Note(VD->getLocation(), diag::note_declared_at);
6973
}
7074

@@ -231,12 +235,32 @@ bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
231235

232236
bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
233237
assert(Desc);
238+
239+
auto IsConstType = [&S](const VarDecl *VD) -> bool {
240+
if (VD->isConstexpr())
241+
return true;
242+
243+
if (S.getLangOpts().CPlusPlus && !S.getLangOpts().CPlusPlus11)
244+
return false;
245+
246+
QualType T = VD->getType();
247+
if (T.isConstQualified())
248+
return true;
249+
250+
if (const auto *RT = T->getAs<ReferenceType>())
251+
return RT->getPointeeType().isConstQualified();
252+
253+
if (const auto *PT = T->getAs<PointerType>())
254+
return PT->getPointeeType().isConstQualified();
255+
256+
return false;
257+
};
258+
234259
if (const auto *D = Desc->asValueDecl()) {
235260
if (const auto *VD = dyn_cast<VarDecl>(D);
236-
VD && VD->hasGlobalStorage() &&
237-
!(VD->isConstexpr() || VD->getType().isConstQualified())) {
261+
VD && VD->hasGlobalStorage() && !IsConstType(VD)) {
238262
diagnoseNonConstVariable(S, OpPC, VD);
239-
return false;
263+
return S.inConstantContext();
240264
}
241265
}
242266

clang/test/AST/Interp/cxx11.cpp

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=both,expected -std=c++11 %s
2+
// RUN: %clang_cc1 -verify=both,ref -std=c++11 %s
3+
4+
// expected-no-diagnostics
5+
6+
namespace IntOrEnum {
7+
const int k = 0;
8+
const int &p = k;
9+
template<int n> struct S {};
10+
S<p> s;
11+
}
12+
13+
const int cval = 2;
14+
template <int> struct C{};
15+
template struct C<cval>;
16+
17+
18+
/// FIXME: This example does not get properly diagnosed in the new interpreter.
19+
extern const int recurse1;
20+
const int recurse2 = recurse1; // ref-note {{here}}
21+
const int recurse1 = 1;
22+
int array1[recurse1];
23+
int array2[recurse2]; // ref-warning 2{{variable length array}} \
24+
// ref-note {{initializer of 'recurse2' is not a constant expression}}

clang/test/AST/Interp/cxx98.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=both,expected -std=c++98 %s
2+
// RUN: %clang_cc1 -verify=both,ref -std=c++98 %s
3+
4+
5+
6+
namespace IntOrEnum {
7+
const int k = 0;
8+
const int &p = k; // both-note {{declared here}}
9+
template<int n> struct S {};
10+
S<p> s; // both-error {{not an integral constant expression}} \
11+
// both-note {{read of variable 'p' of non-integral, non-enumeration type 'const int &'}}
12+
}
13+
14+
const int cval = 2;
15+
template <int> struct C{};
16+
template struct C<cval>;
17+
18+
19+
/// FIXME: This example does not get properly diagnosed in the new interpreter.
20+
extern const int recurse1;
21+
const int recurse2 = recurse1; // ref-note {{here}}
22+
const int recurse1 = 1;
23+
int array1[recurse1];
24+
int array2[recurse2]; // ref-warning 2{{variable length array}} \
25+
// ref-note {{initializer of 'recurse2' is not a constant expression}} \
26+
// expected-warning {{variable length array}} \
27+
// expected-error {{variable length array}}
28+
29+
int NCI; // both-note {{declared here}}
30+
int NCIA[NCI]; // both-warning {{variable length array}} \
31+
// both-error {{variable length array}} \\
32+
// both-note {{read of non-const variable 'NCI'}}

0 commit comments

Comments
 (0)