Skip to content

Commit c51d396

Browse files
authored
[clang][bytecode] Fix __builtin_memmove type diagnostics (#132544)
Set the source type when allocating primitives so we can later retrieve it.
1 parent 51aab96 commit c51d396

File tree

7 files changed

+51
-33
lines changed

7 files changed

+51
-33
lines changed

clang/lib/AST/ByteCode/Compiler.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3356,7 +3356,8 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) {
33563356
if (E->isArray())
33573357
Desc = nullptr; // We're not going to use it in this case.
33583358
else
3359-
Desc = P.createDescriptor(E, *ElemT, Descriptor::InlineDescMD,
3359+
Desc = P.createDescriptor(E, *ElemT, /*SourceTy=*/nullptr,
3360+
Descriptor::InlineDescMD,
33603361
/*IsConst=*/false, /*IsTemporary=*/false,
33613362
/*IsMutable=*/false);
33623363
} else {
@@ -4260,8 +4261,8 @@ unsigned Compiler<Emitter>::allocateLocalPrimitive(
42604261
// FIXME: There are cases where Src.is<Expr*>() is wrong, e.g.
42614262
// (int){12} in C. Consider using Expr::isTemporaryObject() instead
42624263
// or isa<MaterializeTemporaryExpr>().
4263-
Descriptor *D = P.createDescriptor(Src, Ty, Descriptor::InlineDescMD, IsConst,
4264-
isa<const Expr *>(Src));
4264+
Descriptor *D = P.createDescriptor(Src, Ty, nullptr, Descriptor::InlineDescMD,
4265+
IsConst, isa<const Expr *>(Src));
42654266
Scope::Local Local = this->createLocal(D);
42664267
if (auto *VD = dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>()))
42674268
Locals.insert({VD, Local});

clang/lib/AST/ByteCode/Descriptor.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -329,9 +329,10 @@ static BlockMoveFn getMoveArrayPrim(PrimType Type) {
329329
}
330330

331331
/// Primitives.
332-
Descriptor::Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD,
333-
bool IsConst, bool IsTemporary, bool IsMutable)
334-
: Source(D), ElemSize(primSize(Type)), Size(ElemSize),
332+
Descriptor::Descriptor(const DeclTy &D, const Type *SourceTy, PrimType Type,
333+
MetadataSize MD, bool IsConst, bool IsTemporary,
334+
bool IsMutable)
335+
: Source(D), SourceType(SourceTy), ElemSize(primSize(Type)), Size(ElemSize),
335336
MDSize(MD.value_or(0)), AllocSize(align(Size + MDSize)), PrimT(Type),
336337
IsConst(IsConst), IsMutable(IsMutable), IsTemporary(IsTemporary),
337338
CtorFn(getCtorPrim(Type)), DtorFn(getDtorPrim(Type)),

clang/lib/AST/ByteCode/Descriptor.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,8 @@ struct Descriptor final {
175175
const BlockMoveFn MoveFn = nullptr;
176176

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

181181
/// Allocates a descriptor for an array of primitives.
182182
Descriptor(const DeclTy &D, PrimType Type, MetadataSize MD, size_t NumElems,

clang/lib/AST/ByteCode/InterpBuiltin.cpp

Lines changed: 18 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,18 @@ static bool retPrimValue(InterpState &S, CodePtr OpPC,
149149
#undef RET_CASE
150150
}
151151

152+
static QualType getElemType(const Pointer &P) {
153+
const Descriptor *Desc = P.getFieldDesc();
154+
QualType T = Desc->getType();
155+
if (Desc->isPrimitive())
156+
return T;
157+
if (T->isPointerType())
158+
return T->getAs<PointerType>()->getPointeeType();
159+
if (Desc->isArray())
160+
return Desc->getElemQualType();
161+
return T;
162+
}
163+
152164
static void diagnoseNonConstexprBuiltin(InterpState &S, CodePtr OpPC,
153165
unsigned ID) {
154166
auto Loc = S.Current->getSource(OpPC);
@@ -1575,10 +1587,10 @@ static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC,
15751587
return true;
15761588
}
15771589

1578-
const Descriptor *Desc =
1579-
S.P.createDescriptor(NewCall, *ElemT, Descriptor::InlineDescMD,
1580-
/*IsConst=*/false, /*IsTemporary=*/false,
1581-
/*IsMutable=*/false);
1590+
const Descriptor *Desc = S.P.createDescriptor(
1591+
NewCall, *ElemT, ElemType.getTypePtr(), Descriptor::InlineDescMD,
1592+
/*IsConst=*/false, /*IsTemporary=*/false,
1593+
/*IsMutable=*/false);
15821594
Block *B = Allocator.allocate(Desc, S.getContext().getEvalID(),
15831595
DynamicAllocator::Form::Operator);
15841596
assert(B);
@@ -1782,15 +1794,13 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
17821794
if (DestPtr.isDummy() || SrcPtr.isDummy())
17831795
return false;
17841796

1785-
QualType DestElemType;
1797+
QualType DestElemType = getElemType(DestPtr);
17861798
size_t RemainingDestElems;
17871799
if (DestPtr.getFieldDesc()->isArray()) {
1788-
DestElemType = DestPtr.getFieldDesc()->getElemQualType();
17891800
RemainingDestElems = DestPtr.isUnknownSizeArray()
17901801
? 0
17911802
: (DestPtr.getNumElems() - DestPtr.getIndex());
17921803
} else {
1793-
DestElemType = DestPtr.getType();
17941804
RemainingDestElems = 1;
17951805
}
17961806
unsigned DestElemSize = ASTCtx.getTypeSizeInChars(DestElemType).getQuantity();
@@ -1803,15 +1813,13 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
18031813
return false;
18041814
}
18051815

1806-
QualType SrcElemType;
1816+
QualType SrcElemType = getElemType(SrcPtr);
18071817
size_t RemainingSrcElems;
18081818
if (SrcPtr.getFieldDesc()->isArray()) {
1809-
SrcElemType = SrcPtr.getFieldDesc()->getElemQualType();
18101819
RemainingSrcElems = SrcPtr.isUnknownSizeArray()
18111820
? 0
18121821
: (SrcPtr.getNumElems() - SrcPtr.getIndex());
18131822
} else {
1814-
SrcElemType = SrcPtr.getType();
18151823
RemainingSrcElems = 1;
18161824
}
18171825
unsigned SrcElemSize = ASTCtx.getTypeSizeInChars(SrcElemType).getQuantity();
@@ -1884,16 +1892,6 @@ static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC,
18841892
bool IsWide =
18851893
(ID == Builtin::BIwmemcmp || ID == Builtin::BI__builtin_wmemcmp);
18861894

1887-
auto getElemType = [](const Pointer &P) -> QualType {
1888-
const Descriptor *Desc = P.getFieldDesc();
1889-
QualType T = Desc->getType();
1890-
if (T->isPointerType())
1891-
return T->getAs<PointerType>()->getPointeeType();
1892-
if (Desc->isArray())
1893-
return Desc->getElemQualType();
1894-
return T;
1895-
};
1896-
18971895
const ASTContext &ASTCtx = S.getASTContext();
18981896
QualType ElemTypeA = getElemType(PtrA);
18991897
QualType ElemTypeB = getElemType(PtrB);

clang/lib/AST/ByteCode/Program.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ unsigned Program::getOrCreateDummy(const DeclTy &D) {
166166

167167
Descriptor *Desc;
168168
if (std::optional<PrimType> T = Ctx.classify(QT))
169-
Desc = createDescriptor(D, *T, std::nullopt, /*IsTemporary=*/true,
169+
Desc = createDescriptor(D, *T, nullptr, std::nullopt, /*IsTemporary=*/true,
170170
/*IsMutable=*/false);
171171
else
172172
Desc = createDescriptor(D, QT.getTypePtr(), std::nullopt,
@@ -244,7 +244,8 @@ std::optional<unsigned> Program::createGlobal(const DeclTy &D, QualType Ty,
244244
const bool IsConst = Ty.isConstQualified();
245245
const bool IsTemporary = D.dyn_cast<const Expr *>();
246246
if (std::optional<PrimType> T = Ctx.classify(Ty))
247-
Desc = createDescriptor(D, *T, Descriptor::GlobalMD, IsConst, IsTemporary);
247+
Desc = createDescriptor(D, *T, nullptr, Descriptor::GlobalMD, IsConst,
248+
IsTemporary);
248249
else
249250
Desc = createDescriptor(D, Ty.getTypePtr(), Descriptor::GlobalMD, IsConst,
250251
IsTemporary);
@@ -365,7 +366,7 @@ Record *Program::getOrCreateRecord(const RecordDecl *RD) {
365366
const bool IsMutable = FD->isMutable();
366367
const Descriptor *Desc;
367368
if (std::optional<PrimType> T = Ctx.classify(FT)) {
368-
Desc = createDescriptor(FD, *T, std::nullopt, IsConst,
369+
Desc = createDescriptor(FD, *T, nullptr, std::nullopt, IsConst,
369370
/*isTemporary=*/false, IsMutable);
370371
} else {
371372
Desc = createDescriptor(FD, FT.getTypePtr(), std::nullopt, IsConst,

clang/lib/AST/ByteCode/Program.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -115,11 +115,13 @@ class Program final {
115115
Record *getOrCreateRecord(const RecordDecl *RD);
116116

117117
/// Creates a descriptor for a primitive type.
118-
Descriptor *createDescriptor(const DeclTy &D, PrimType Type,
118+
Descriptor *createDescriptor(const DeclTy &D, PrimType T,
119+
const Type *SourceTy = nullptr,
119120
Descriptor::MetadataSize MDSize = std::nullopt,
120121
bool IsConst = false, bool IsTemporary = false,
121122
bool IsMutable = false) {
122-
return allocateDescriptor(D, Type, MDSize, IsConst, IsTemporary, IsMutable);
123+
return allocateDescriptor(D, SourceTy, T, MDSize, IsConst, IsTemporary,
124+
IsMutable);
123125
}
124126

125127
/// Creates a descriptor for a composite type.

clang/test/AST/ByteCode/placement-new.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -376,3 +376,18 @@ constexpr int N = [] // expected-error {{must be initialized by a constant expre
376376
return s.a[0];
377377
}();
378378
#endif
379+
380+
namespace MemMove {
381+
constexpr int foo() {
382+
int *a = std::allocator<int>{}.allocate(1);
383+
new(a) int{123};
384+
385+
int b;
386+
__builtin_memmove(&b, a, sizeof(int));
387+
388+
std::allocator<int>{}.deallocate(a);
389+
return b;
390+
}
391+
392+
static_assert(foo() == 123);
393+
}

0 commit comments

Comments
 (0)