Skip to content

Commit cb608cc

Browse files
authored
[clang][bytecode] Properly diagnose non-const reads (#106514)
If the global variable is constant (but not constexpr), we need to diagnose, but keep evaluating.
1 parent 9167667 commit cb608cc

File tree

2 files changed

+52
-23
lines changed

2 files changed

+52
-23
lines changed

clang/lib/AST/ByteCode/Interp.cpp

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -323,36 +323,52 @@ bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
323323
bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
324324
assert(Desc);
325325

326-
auto IsConstType = [&S](const VarDecl *VD) -> bool {
327-
QualType T = VD->getType();
328-
329-
if (T.isConstant(S.getASTContext()))
330-
return true;
331-
332-
if (S.getLangOpts().CPlusPlus && !S.getLangOpts().CPlusPlus11)
333-
return (T->isSignedIntegerOrEnumerationType() ||
334-
T->isUnsignedIntegerOrEnumerationType()) &&
335-
T.isConstQualified();
326+
const auto *D = Desc->asVarDecl();
327+
if (!D || !D->hasGlobalStorage())
328+
return true;
336329

337-
if (T.isConstQualified())
338-
return true;
330+
if (D == S.EvaluatingDecl)
331+
return true;
339332

340-
if (const auto *RT = T->getAs<ReferenceType>())
341-
return RT->getPointeeType().isConstQualified();
333+
if (D->isConstexpr())
334+
return true;
342335

343-
if (const auto *PT = T->getAs<PointerType>())
344-
return PT->getPointeeType().isConstQualified();
336+
QualType T = D->getType();
337+
bool IsConstant = T.isConstant(S.getASTContext());
338+
if (T->isIntegralOrEnumerationType()) {
339+
if (!IsConstant) {
340+
diagnoseNonConstVariable(S, OpPC, D);
341+
return false;
342+
}
343+
return true;
344+
}
345345

346-
return false;
347-
};
346+
if (IsConstant) {
347+
if (S.getLangOpts().CPlusPlus) {
348+
S.CCEDiag(S.Current->getLocation(OpPC),
349+
S.getLangOpts().CPlusPlus11
350+
? diag::note_constexpr_ltor_non_constexpr
351+
: diag::note_constexpr_ltor_non_integral,
352+
1)
353+
<< D << T;
354+
S.Note(D->getLocation(), diag::note_declared_at);
355+
} else {
356+
S.CCEDiag(S.Current->getLocation(OpPC));
357+
}
358+
return true;
359+
}
348360

349-
if (const auto *D = Desc->asVarDecl();
350-
D && D->hasGlobalStorage() && D != S.EvaluatingDecl && !IsConstType(D)) {
351-
diagnoseNonConstVariable(S, OpPC, D);
352-
return false;
361+
if (T->isPointerOrReferenceType()) {
362+
if (!T->getPointeeType().isConstant(S.getASTContext()) ||
363+
!S.getLangOpts().CPlusPlus11) {
364+
diagnoseNonConstVariable(S, OpPC, D);
365+
return false;
366+
}
367+
return true;
353368
}
354369

355-
return true;
370+
diagnoseNonConstVariable(S, OpPC, D);
371+
return false;
356372
}
357373

358374
static bool CheckConstant(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=both,expected -std=c++11 -triple x86_64-linux -pedantic %s
2+
// RUN: %clang_cc1 -verify=both,ref -std=c++11 -triple x86_64-linux -pedantic %s
3+
4+
struct T { int n; };
5+
const T t = { 42 }; // both-note 2{{declared here}}
6+
struct S {
7+
int m : t.n; // both-warning {{width of bit-field 'm' (42 bits)}} \
8+
// both-warning {{expression is not an integral constant expression}} \
9+
// both-note {{read of non-constexpr variable 't' is not allowed}}
10+
};
11+
12+
static_assert(t.n == 42, ""); // both-error {{expression is not an integral constant expression}} \
13+
// both-note {{read of non-constexpr variable 't' is not allowed}}

0 commit comments

Comments
 (0)