Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 38 additions & 15 deletions clang/lib/AST/ByteCode/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "clang/Basic/Builtins.h"
#include "clang/Basic/TargetBuiltins.h"
#include "clang/Basic/TargetInfo.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/SipHash.h"

namespace clang {
Expand Down Expand Up @@ -1837,6 +1838,7 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
assert(Call->getNumArgs() == 3);
unsigned ID = Func->getBuiltinID();
Pointer DestPtr = getParam<Pointer>(Frame, 0);
const ASTContext &ASTCtx = S.getASTContext();
const Pointer &SrcPtr = getParam<Pointer>(Frame, 1);
const APSInt &Size =
peekToAPSInt(S.Stk, *S.getContext().classify(Call->getArg(2)));
Expand All @@ -1857,34 +1859,55 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
Pointer DiagPtr = (SrcPtr.isZero() ? SrcPtr : DestPtr);
S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_null)
<< /*IsMove=*/Move << /*IsWchar=*/false << !SrcPtr.isZero()
<< DiagPtr.toDiagnosticString(S.getASTContext());
<< DiagPtr.toDiagnosticString(ASTCtx);
return false;
}

QualType ElemType;
if (DestPtr.getFieldDesc()->isArray())
ElemType = DestPtr.getFieldDesc()->getElemQualType();
else
ElemType = DestPtr.getType();
QualType DestElemType;
size_t RemainingDestElems;
if (DestPtr.getFieldDesc()->isArray()) {
DestElemType = DestPtr.getFieldDesc()->getElemQualType();
RemainingDestElems = (DestPtr.getNumElems() - DestPtr.getIndex());
} else {
DestElemType = DestPtr.getType();
RemainingDestElems = 1;
}
unsigned DestElemSize = ASTCtx.getTypeSizeInChars(DestElemType).getQuantity();

unsigned ElemSize =
S.getASTContext().getTypeSizeInChars(ElemType).getQuantity();
if (Size.urem(ElemSize) != 0) {
if (Size.urem(DestElemSize) != 0) {
S.FFDiag(S.Current->getSource(OpPC),
diag::note_constexpr_memcpy_unsupported)
<< Move << /*IsWchar=*/false << 0 << ElemType << Size << ElemSize;
<< Move << /*IsWchar=*/false << 0 << DestElemType << Size
<< DestElemSize;
return false;
}

QualType SrcElemType;
if (SrcPtr.getFieldDesc()->isArray())
size_t RemainingSrcElems;
if (SrcPtr.getFieldDesc()->isArray()) {
SrcElemType = SrcPtr.getFieldDesc()->getElemQualType();
else
RemainingSrcElems = (SrcPtr.getNumElems() - SrcPtr.getIndex());
} else {
SrcElemType = SrcPtr.getType();
RemainingSrcElems = 1;
}
unsigned SrcElemSize = ASTCtx.getTypeSizeInChars(SrcElemType).getQuantity();

if (!S.getASTContext().hasSameUnqualifiedType(ElemType, SrcElemType)) {
if (!ASTCtx.hasSameUnqualifiedType(DestElemType, SrcElemType)) {
S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_memcpy_type_pun)
<< Move << SrcElemType << ElemType;
<< Move << SrcElemType << DestElemType;
return false;
}

// Check if we have enough elements to read from and write to/
size_t RemainingDestBytes = RemainingDestElems * DestElemSize;
size_t RemainingSrcBytes = RemainingSrcElems * SrcElemSize;
if (Size.ugt(RemainingDestBytes) || Size.ugt(RemainingSrcBytes)) {
APInt N = Size.udiv(DestElemSize);
S.FFDiag(S.Current->getSource(OpPC),
diag::note_constexpr_memcpy_unsupported)
<< Move << /*IsWChar*/ false << (Size.ugt(RemainingSrcBytes) ? 1 : 2)
<< DestElemType << toString(N, 10, /*Signed=*/false);
return false;
}

Expand All @@ -1905,7 +1928,7 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
// As a last resort, reject dummy pointers.
if (DestPtr.isDummy() || SrcPtr.isDummy())
return false;
assert(Size.getZExtValue() % ElemSize == 0);
assert(Size.getZExtValue() % DestElemSize == 0);
if (!DoMemcpy(S, OpPC, SrcPtr, DestPtr, Bytes(Size.getZExtValue()).toBits()))
return false;

Expand Down
9 changes: 9 additions & 0 deletions clang/test/AST/ByteCode/builtin-functions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1244,6 +1244,15 @@ namespace BuiltinMemcpy {
}
static_assert(cpyptr());

#ifndef __AVR__
constexpr int test_memmove(int a, int b, int n) {
int arr[4] = {1, 2, 3, 4};
__builtin_memmove(arr + a, arr + b, n); // both-note {{destination is not a contiguous array of at least 3 elements of type 'int'}}
return result(arr);
}
static_assert(test_memmove(2, 0, 12) == 4234); // both-error {{constant}} \
// both-note {{in call}}
#endif
}

namespace Memcmp {
Expand Down
Loading