Skip to content

[clang][bytecode] Fix __builtin_memmove type diagnostics #132544

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Mar 22, 2025
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
7 changes: 4 additions & 3 deletions clang/lib/AST/ByteCode/Compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3354,7 +3354,8 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) {
if (E->isArray())
Desc = nullptr; // We're not going to use it in this case.
else
Desc = P.createDescriptor(E, *ElemT, Descriptor::InlineDescMD,
Desc = P.createDescriptor(E, *ElemT, /*SourceTy=*/nullptr,
Descriptor::InlineDescMD,
/*IsConst=*/false, /*IsTemporary=*/false,
/*IsMutable=*/false);
} else {
Expand Down Expand Up @@ -4258,8 +4259,8 @@ unsigned Compiler<Emitter>::allocateLocalPrimitive(
// FIXME: There are cases where Src.is<Expr*>() is wrong, e.g.
// (int){12} in C. Consider using Expr::isTemporaryObject() instead
// or isa<MaterializeTemporaryExpr>().
Descriptor *D = P.createDescriptor(Src, Ty, Descriptor::InlineDescMD, IsConst,
isa<const Expr *>(Src));
Descriptor *D = P.createDescriptor(Src, Ty, nullptr, Descriptor::InlineDescMD,
IsConst, isa<const Expr *>(Src));
Scope::Local Local = this->createLocal(D);
if (auto *VD = dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>()))
Locals.insert({VD, Local});
Expand Down
7 changes: 4 additions & 3 deletions clang/lib/AST/ByteCode/Descriptor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -329,9 +329,10 @@ static BlockMoveFn getMoveArrayPrim(PrimType Type) {
}

/// Primitives.
Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD,
bool IsConst, bool IsTemporary, bool IsMutable)
: Source(D), ElemSize(primSize(Type)), Size(ElemSize),
Descriptor::Descriptor(const DeclTy &D, const Type *SourceTy, PrimType Type,
MetadataSize MD, bool IsConst, bool IsTemporary,
bool IsMutable)
: Source(D), SourceType(SourceTy), ElemSize(primSize(Type)), Size(ElemSize),
MDSize(MD.value_or(0)), AllocSize(align(Size + MDSize)), PrimT(Type),
IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),
CtorFn(getCtorPrim(Type)), DtorFn(getDtorPrim(Type)),
Expand Down
4 changes: 2 additions & 2 deletions clang/lib/AST/ByteCode/Descriptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,8 @@ struct Descriptor final {
const BlockMoveFn MoveFn = nullptr;

/// Allocates a descriptor for a primitive.
Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD, bool IsConst,
bool IsTemporary, bool IsMutable);
Descriptor(const DeclTy &D, const Type *SourceTy, PrimType Type,
MetadataSize MD, bool IsConst, bool IsTemporary, bool IsMutable);

/// Allocates a descriptor for an array of primitives.
Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD, size_t NumElems,
Expand Down
38 changes: 18 additions & 20 deletions clang/lib/AST/ByteCode/InterpBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,18 @@ static bool retPrimValue(InterpState &S, CodePtr OpPC,
#undef RET_CASE
}

static QualType getElemType(const Pointer &P) {
const Descriptor *Desc = P.getFieldDesc();
QualType T = Desc->getType();
if (Desc->isPrimitive())
return T;
if (T->isPointerType())
return T->getAs<PointerType>()->getPointeeType();
if (Desc->isArray())
return Desc->getElemQualType();
return T;
}

static void diagnoseNonConstexprBuiltin(InterpState &S, CodePtr OpPC,
unsigned ID) {
auto Loc = S.Current->getSource(OpPC);
Expand Down Expand Up @@ -1572,10 +1584,10 @@ static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC,
return true;
}

const Descriptor *Desc =
S.P.createDescriptor(NewCall, *ElemT, Descriptor::InlineDescMD,
/*IsConst=*/false, /*IsTemporary=*/false,
/*IsMutable=*/false);
const Descriptor *Desc = S.P.createDescriptor(
NewCall, *ElemT, ElemType.getTypePtr(), Descriptor::InlineDescMD,
/*IsConst=*/false, /*IsTemporary=*/false,
/*IsMutable=*/false);
Block *B = Allocator.allocate(Desc, S.getContext().getEvalID(),
DynamicAllocator::Form::Operator);
assert(B);
Expand Down Expand Up @@ -1779,15 +1791,13 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
if (DestPtr.isDummy() || SrcPtr.isDummy())
return false;

QualType DestElemType;
QualType DestElemType = getElemType(DestPtr);
size_t RemainingDestElems;
if (DestPtr.getFieldDesc()->isArray()) {
DestElemType = DestPtr.getFieldDesc()->getElemQualType();
RemainingDestElems = DestPtr.isUnknownSizeArray()
? 0
: (DestPtr.getNumElems() - DestPtr.getIndex());
} else {
DestElemType = DestPtr.getType();
RemainingDestElems = 1;
}
unsigned DestElemSize = ASTCtx.getTypeSizeInChars(DestElemType).getQuantity();
Expand All @@ -1800,15 +1810,13 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
return false;
}

QualType SrcElemType;
QualType SrcElemType = getElemType(SrcPtr);
size_t RemainingSrcElems;
if (SrcPtr.getFieldDesc()->isArray()) {
SrcElemType = SrcPtr.getFieldDesc()->getElemQualType();
RemainingSrcElems = SrcPtr.isUnknownSizeArray()
? 0
: (SrcPtr.getNumElems() - SrcPtr.getIndex());
} else {
SrcElemType = SrcPtr.getType();
RemainingSrcElems = 1;
}
unsigned SrcElemSize = ASTCtx.getTypeSizeInChars(SrcElemType).getQuantity();
Expand Down Expand Up @@ -1881,16 +1889,6 @@ static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC,
bool IsWide =
(ID == Builtin::BIwmemcmp || ID == Builtin::BI__builtin_wmemcmp);

auto getElemType = [](const Pointer &P) -> QualType {
const Descriptor *Desc = P.getFieldDesc();
QualType T = Desc->getType();
if (T->isPointerType())
return T->getAs<PointerType>()->getPointeeType();
if (Desc->isArray())
return Desc->getElemQualType();
return T;
};

const ASTContext &ASTCtx = S.getASTContext();
QualType ElemTypeA = getElemType(PtrA);
QualType ElemTypeB = getElemType(PtrB);
Expand Down
7 changes: 4 additions & 3 deletions clang/lib/AST/ByteCode/Program.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ unsigned Program::getOrCreateDummy(const DeclTy &D) {

Descriptor *Desc;
if (std::optional<PrimType> T = Ctx.classify(QT))
Desc = createDescriptor(D, *T, std::nullopt, /*IsTemporary=*/true,
Desc = createDescriptor(D, *T, nullptr, std::nullopt, /*IsTemporary=*/true,
/*IsMutable=*/false);
else
Desc = createDescriptor(D, QT.getTypePtr(), std::nullopt,
Expand Down Expand Up @@ -244,7 +244,8 @@ std::optional<unsigned> Program::createGlobal(const DeclTy &D, QualType Ty,
const bool IsConst = Ty.isConstQualified();
const bool IsTemporary = D.dyn_cast<const Expr *>();
if (std::optional<PrimType> T = Ctx.classify(Ty))
Desc = createDescriptor(D, *T, Descriptor::GlobalMD, IsConst, IsTemporary);
Desc = createDescriptor(D, *T, nullptr, Descriptor::GlobalMD, IsConst,
IsTemporary);
else
Desc = createDescriptor(D, Ty.getTypePtr(), Descriptor::GlobalMD, IsConst,
IsTemporary);
Expand Down Expand Up @@ -365,7 +366,7 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) {
const bool IsMutable = FD->isMutable();
const Descriptor *Desc;
if (std::optional<PrimType> T = Ctx.classify(FT)) {
Desc = createDescriptor(FD, *T, std::nullopt, IsConst,
Desc = createDescriptor(FD, *T, nullptr, std::nullopt, IsConst,
/*isTemporary=*/false, IsMutable);
} else {
Desc = createDescriptor(FD, FT.getTypePtr(), std::nullopt, IsConst,
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/AST/ByteCode/Program.h
Original file line number Diff line number Diff line change
Expand Up @@ -115,11 +115,13 @@ class Program final {
Record *getOrCreateRecord(const RecordDecl *RD);

/// Creates a descriptor for a primitive type.
Descriptor *createDescriptor(const DeclTy &D, PrimType Type,
Descriptor *createDescriptor(const DeclTy &D, PrimType T,
const Type *SourceTy = nullptr,
Descriptor::MetadataSize MDSize = std::nullopt,
bool IsConst = false, bool IsTemporary = false,
bool IsMutable = false) {
return allocateDescriptor(D, Type, MDSize, IsConst, IsTemporary, IsMutable);
return allocateDescriptor(D, SourceTy, T, MDSize, IsConst, IsTemporary,
IsMutable);
}

/// Creates a descriptor for a composite type.
Expand Down
15 changes: 15 additions & 0 deletions clang/test/AST/ByteCode/placement-new.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -376,3 +376,18 @@ constexpr int N = [] // expected-error {{must be initialized by a constant expre
return s.a[0];
}();
#endif

namespace MemMove {
constexpr int foo() {
int *a = std::allocator<int>{}.allocate(1);
new(a) int{123};

int b;
__builtin_memmove(&b, a, sizeof(int));

std::allocator<int>{}.deallocate(a);
return b;
}

static_assert(foo() == 123);
}