Skip to content

Commit

Permalink
[clang][Interp] Handle unknown-size arrays better (#68868)
Browse files Browse the repository at this point in the history
We unfortunately actually need to do some checks for array-to-pointer
decays it seems.
  • Loading branch information
tbaederr committed Oct 26, 2023
1 parent 8149066 commit 658874e
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 1 deletion.
14 changes: 13 additions & 1 deletion clang/lib/AST/Interp/ByteCodeExprGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,16 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
return this->emitCastPointerIntegral(T, CE);
}

case CK_ArrayToPointerDecay:
case CK_ArrayToPointerDecay: {
if (!this->visit(SubExpr))
return false;
if (!this->emitArrayDecay(CE))
return false;
if (DiscardResult)
return this->emitPopPtr(CE);
return true;
}

case CK_AtomicToNonAtomic:
case CK_ConstructorConversion:
case CK_FunctionToPointerDecay:
Expand Down Expand Up @@ -505,6 +514,9 @@ bool ByteCodeExprGen<Emitter>::VisitImplicitValueInitExpr(const ImplicitValueIni
if (QT->isRecordType())
return false;

if (QT->isIncompleteArrayType())
return true;

if (QT->isArrayType()) {
const ArrayType *AT = QT->getAsArrayTypeUnsafe();
assert(AT);
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/AST/Interp/EvalEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,12 @@ bool EvalEmitter::emitRetValue(const SourceInfo &Info) {
}
return Ok;
}

if (Ty->isIncompleteArrayType()) {
R = APValue(APValue::UninitArray(), 0, 0);
return true;
}

if (const auto *AT = Ty->getAsArrayTypeUnsafe()) {
const size_t NumElems = Ptr.getNumElems();
QualType ElemTy = AT->getElementType();
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/Interp/Interp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,8 @@ static bool CheckFieldsInitialized(InterpState &S, CodePtr OpPC,

if (FieldType->isRecordType()) {
Result &= CheckFieldsInitialized(S, OpPC, FieldPtr, FieldPtr.getRecord());
} else if (FieldType->isIncompleteArrayType()) {
// Nothing to do here.
} else if (FieldType->isArrayType()) {
const auto *CAT =
cast<ConstantArrayType>(FieldType->getAsArrayTypeUnsafe());
Expand Down
20 changes: 20 additions & 0 deletions clang/lib/AST/Interp/Interp.h
Original file line number Diff line number Diff line change
Expand Up @@ -1802,17 +1802,37 @@ inline bool ArrayElemPtr(InterpState &S, CodePtr OpPC) {
const T &Offset = S.Stk.pop<T>();
const Pointer &Ptr = S.Stk.peek<Pointer>();

if (!CheckArray(S, OpPC, Ptr))
return false;

if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
return false;

return NarrowPtr(S, OpPC);
}

/// Just takes a pointer and checks if its' an incomplete
/// array type.
inline bool ArrayDecay(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.peek<Pointer>();

if (!Ptr.isUnknownSizeArray())
return true;

const SourceInfo &E = S.Current->getSource(OpPC);
S.FFDiag(E, diag::note_constexpr_unsupported_unsized_array);

return false;
}

template <PrimType Name, class T = typename PrimConv<Name>::T>
inline bool ArrayElemPtrPop(InterpState &S, CodePtr OpPC) {
const T &Offset = S.Stk.pop<T>();
const Pointer &Ptr = S.Stk.pop<Pointer>();

if (!CheckArray(S, OpPC, Ptr))
return false;

if (!OffsetHelper<T, ArithOp::Add>(S, OpPC, Offset, Ptr))
return false;

Expand Down
2 changes: 2 additions & 0 deletions clang/lib/AST/Interp/Opcodes.td
Original file line number Diff line number Diff line change
Expand Up @@ -687,3 +687,5 @@ def InvalidCast : Opcode {
def InvalidDeclRef : Opcode {
let Args = [ArgDeclRef];
}

def ArrayDecay : Opcode;
42 changes: 42 additions & 0 deletions clang/test/AST/Interp/arrays.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -455,3 +455,45 @@ namespace NoInitMapLeak {
// ref-error {{not an integral constant expression}} \
// ref-note {{in call to}}
}

namespace Incomplete {
struct Foo {
char c;
int a[];
};

constexpr Foo F{};
constexpr const int *A = F.a; // ref-error {{must be initialized by a constant expression}} \
// ref-note {{array-to-pointer decay of array member without known bound}} \
// expected-error {{must be initialized by a constant expression}} \
// expected-note {{array-to-pointer decay of array member without known bound}}

constexpr const int *B = F.a + 1; // ref-error {{must be initialized by a constant expression}} \
// ref-note {{array-to-pointer decay of array member without known bound}} \
// expected-error {{must be initialized by a constant expression}} \
// expected-note {{array-to-pointer decay of array member without known bound}}

constexpr int C = *F.a; // ref-error {{must be initialized by a constant expression}} \
// ref-note {{array-to-pointer decay of array member without known bound}} \
// expected-error {{must be initialized by a constant expression}} \
// expected-note {{array-to-pointer decay of array member without known bound}}



/// These are from test/SemaCXX/constant-expression-cxx11.cpp
/// and are the only tests using the 'indexing of array without known bound' diagnostic.
/// We currently diagnose them differently.
extern int arr[]; // expected-note 3{{declared here}}
constexpr int *c = &arr[1]; // ref-error {{must be initialized by a constant expression}} \
// ref-note {{indexing of array without known bound}} \
// expected-error {{must be initialized by a constant expression}} \
// expected-note {{read of non-constexpr variable 'arr'}}
constexpr int *d = &arr[1]; // ref-error {{must be initialized by a constant expression}} \
// ref-note {{indexing of array without known bound}} \
// expected-error {{must be initialized by a constant expression}} \
// expected-note {{read of non-constexpr variable 'arr'}}
constexpr int *e = arr + 1; // ref-error {{must be initialized by a constant expression}} \
// ref-note {{indexing of array without known bound}} \
// expected-error {{must be initialized by a constant expression}} \
// expected-note {{read of non-constexpr variable 'arr'}}
}

0 comments on commit 658874e

Please sign in to comment.