Skip to content

Commit 658874e

Browse files
authored
[clang][Interp] Handle unknown-size arrays better (#68868)
We unfortunately actually need to do some checks for array-to-pointer decays it seems.
1 parent 8149066 commit 658874e

File tree

6 files changed

+85
-1
lines changed

6 files changed

+85
-1
lines changed

clang/lib/AST/Interp/ByteCodeExprGen.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,16 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
168168
return this->emitCastPointerIntegral(T, CE);
169169
}
170170

171-
case CK_ArrayToPointerDecay:
171+
case CK_ArrayToPointerDecay: {
172+
if (!this->visit(SubExpr))
173+
return false;
174+
if (!this->emitArrayDecay(CE))
175+
return false;
176+
if (DiscardResult)
177+
return this->emitPopPtr(CE);
178+
return true;
179+
}
180+
172181
case CK_AtomicToNonAtomic:
173182
case CK_ConstructorConversion:
174183
case CK_FunctionToPointerDecay:
@@ -505,6 +514,9 @@ bool ByteCodeExprGen<Emitter>::VisitImplicitValueInitExpr(const ImplicitValueIni
505514
if (QT->isRecordType())
506515
return false;
507516

517+
if (QT->isIncompleteArrayType())
518+
return true;
519+
508520
if (QT->isArrayType()) {
509521
const ArrayType *AT = QT->getAsArrayTypeUnsafe();
510522
assert(AT);

clang/lib/AST/Interp/EvalEmitter.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,12 @@ bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
185185
}
186186
return Ok;
187187
}
188+
189+
if (Ty->isIncompleteArrayType()) {
190+
R = APValue(APValue::UninitArray(), 0, 0);
191+
return true;
192+
}
193+
188194
if (const auto *AT = Ty->getAsArrayTypeUnsafe()) {
189195
const size_t NumElems = Ptr.getNumElems();
190196
QualType ElemTy = AT->getElementType();

clang/lib/AST/Interp/Interp.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,8 @@ static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC,
483483

484484
if (FieldType->isRecordType()) {
485485
Result &= CheckFieldsInitialized(S, OpPC, FieldPtr, FieldPtr.getRecord());
486+
} else if (FieldType->isIncompleteArrayType()) {
487+
// Nothing to do here.
486488
} else if (FieldType->isArrayType()) {
487489
const auto *CAT =
488490
cast<ConstantArrayType>(FieldType->getAsArrayTypeUnsafe());

clang/lib/AST/Interp/Interp.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1802,17 +1802,37 @@ inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
18021802
const T &Offset = S.Stk.pop<T>();
18031803
const Pointer &Ptr = S.Stk.peek<Pointer>();
18041804

1805+
if (!CheckArray(S, OpPC, Ptr))
1806+
return false;
1807+
18051808
if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
18061809
return false;
18071810

18081811
return NarrowPtr(S, OpPC);
18091812
}
18101813

1814+
/// Just takes a pointer and checks if its' an incomplete
1815+
/// array type.
1816+
inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
1817+
const Pointer &Ptr = S.Stk.peek<Pointer>();
1818+
1819+
if (!Ptr.isUnknownSizeArray())
1820+
return true;
1821+
1822+
const SourceInfo &E = S.Current->getSource(OpPC);
1823+
S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array);
1824+
1825+
return false;
1826+
}
1827+
18111828
template <PrimType Name, class T = typename PrimConv<Name>::T>
18121829
inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
18131830
const T &Offset = S.Stk.pop<T>();
18141831
const Pointer &Ptr = S.Stk.pop<Pointer>();
18151832

1833+
if (!CheckArray(S, OpPC, Ptr))
1834+
return false;
1835+
18161836
if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
18171837
return false;
18181838

clang/lib/AST/Interp/Opcodes.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -687,3 +687,5 @@ def InvalidCast : Opcode {
687687
def InvalidDeclRef : Opcode {
688688
let Args = [ArgDeclRef];
689689
}
690+
691+
def ArrayDecay : Opcode;

clang/test/AST/Interp/arrays.cpp

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,3 +455,45 @@ namespace NoInitMapLeak {
455455
// ref-error {{not an integral constant expression}} \
456456
// ref-note {{in call to}}
457457
}
458+
459+
namespace Incomplete {
460+
struct Foo {
461+
char c;
462+
int a[];
463+
};
464+
465+
constexpr Foo F{};
466+
constexpr const int *A = F.a; // ref-error {{must be initialized by a constant expression}} \
467+
// ref-note {{array-to-pointer decay of array member without known bound}} \
468+
// expected-error {{must be initialized by a constant expression}} \
469+
// expected-note {{array-to-pointer decay of array member without known bound}}
470+
471+
constexpr const int *B = F.a + 1; // ref-error {{must be initialized by a constant expression}} \
472+
// ref-note {{array-to-pointer decay of array member without known bound}} \
473+
// expected-error {{must be initialized by a constant expression}} \
474+
// expected-note {{array-to-pointer decay of array member without known bound}}
475+
476+
constexpr int C = *F.a; // ref-error {{must be initialized by a constant expression}} \
477+
// ref-note {{array-to-pointer decay of array member without known bound}} \
478+
// expected-error {{must be initialized by a constant expression}} \
479+
// expected-note {{array-to-pointer decay of array member without known bound}}
480+
481+
482+
483+
/// These are from test/SemaCXX/constant-expression-cxx11.cpp
484+
/// and are the only tests using the 'indexing of array without known bound' diagnostic.
485+
/// We currently diagnose them differently.
486+
extern int arr[]; // expected-note 3{{declared here}}
487+
constexpr int *c = &arr[1]; // ref-error {{must be initialized by a constant expression}} \
488+
// ref-note {{indexing of array without known bound}} \
489+
// expected-error {{must be initialized by a constant expression}} \
490+
// expected-note {{read of non-constexpr variable 'arr'}}
491+
constexpr int *d = &arr[1]; // ref-error {{must be initialized by a constant expression}} \
492+
// ref-note {{indexing of array without known bound}} \
493+
// expected-error {{must be initialized by a constant expression}} \
494+
// expected-note {{read of non-constexpr variable 'arr'}}
495+
constexpr int *e = arr + 1; // ref-error {{must be initialized by a constant expression}} \
496+
// ref-note {{indexing of array without known bound}} \
497+
// expected-error {{must be initialized by a constant expression}} \
498+
// expected-note {{read of non-constexpr variable 'arr'}}
499+
}

0 commit comments

Comments
 (0)