Skip to content

Commit f3b1b58

Browse files
committed
[clang][bytecode] Fix __builtin_memmove type diagnostics
Set the source type when allocating primitives so we can later retrieve it.
1 parent 2089b08 commit f3b1b58

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
@@ -3354,7 +3354,8 @@ bool Compiler<Emitter>::VisitCXXNewExpr(const CXXNewExpr *E) {
33543354
if (E->isArray())
33553355
Desc = nullptr; // We're not going to use it in this case.
33563356
else
3357-
Desc = P.createDescriptor(E, *ElemT, Descriptor::InlineDescMD,
3357+
Desc = P.createDescriptor(E, *ElemT, /*SourceTy=*/nullptr,
3358+
Descriptor::InlineDescMD,
33583359
/*IsConst=*/false, /*IsTemporary=*/false,
33593360
/*IsMutable=*/false);
33603361
} else {
@@ -4258,8 +4259,8 @@ unsigned Compiler<Emitter>::allocateLocalPrimitive(
42584259
// FIXME: There are cases where Src.is<Expr*>() is wrong, e.g.
42594260
// (int){12} in C. Consider using Expr::isTemporaryObject() instead
42604261
// or isa<MaterializeTemporaryExpr>().
4261-
Descriptor *D = P.createDescriptor(Src, Ty, Descriptor::InlineDescMD, IsConst,
4262-
isa<const Expr *>(Src));
4262+
Descriptor *D = P.createDescriptor(Src, Ty, nullptr, Descriptor::InlineDescMD,
4263+
IsConst, isa<const Expr *>(Src));
42634264
Scope::Local Local = this->createLocal(D);
42644265
if (auto *VD = dyn_cast_if_present<ValueDecl>(Src.dyn_cast<const Decl *>()))
42654266
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);
@@ -1572,10 +1584,10 @@ static bool interp__builtin_operator_new(InterpState &S, CodePtr OpPC,
15721584
return true;
15731585
}
15741586

1575-
const Descriptor *Desc =
1576-
S.P.createDescriptor(NewCall, *ElemT, Descriptor::InlineDescMD,
1577-
/*IsConst=*/false, /*IsTemporary=*/false,
1578-
/*IsMutable=*/false);
1587+
const Descriptor *Desc = S.P.createDescriptor(
1588+
NewCall, *ElemT, ElemType.getTypePtr(), Descriptor::InlineDescMD,
1589+
/*IsConst=*/false, /*IsTemporary=*/false,
1590+
/*IsMutable=*/false);
15791591
Block *B = Allocator.allocate(Desc, S.getContext().getEvalID(),
15801592
DynamicAllocator::Form::Operator);
15811593
assert(B);
@@ -1779,15 +1791,13 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
17791791
if (DestPtr.isDummy() || SrcPtr.isDummy())
17801792
return false;
17811793

1782-
QualType DestElemType;
1794+
QualType DestElemType = getElemType(DestPtr);
17831795
size_t RemainingDestElems;
17841796
if (DestPtr.getFieldDesc()->isArray()) {
1785-
DestElemType = DestPtr.getFieldDesc()->getElemQualType();
17861797
RemainingDestElems = DestPtr.isUnknownSizeArray()
17871798
? 0
17881799
: (DestPtr.getNumElems() - DestPtr.getIndex());
17891800
} else {
1790-
DestElemType = DestPtr.getType();
17911801
RemainingDestElems = 1;
17921802
}
17931803
unsigned DestElemSize = ASTCtx.getTypeSizeInChars(DestElemType).getQuantity();
@@ -1800,15 +1810,13 @@ static bool interp__builtin_memcpy(InterpState &S, CodePtr OpPC,
18001810
return false;
18011811
}
18021812

1803-
QualType SrcElemType;
1813+
QualType SrcElemType = getElemType(SrcPtr);
18041814
size_t RemainingSrcElems;
18051815
if (SrcPtr.getFieldDesc()->isArray()) {
1806-
SrcElemType = SrcPtr.getFieldDesc()->getElemQualType();
18071816
RemainingSrcElems = SrcPtr.isUnknownSizeArray()
18081817
? 0
18091818
: (SrcPtr.getNumElems() - SrcPtr.getIndex());
18101819
} else {
1811-
SrcElemType = SrcPtr.getType();
18121820
RemainingSrcElems = 1;
18131821
}
18141822
unsigned SrcElemSize = ASTCtx.getTypeSizeInChars(SrcElemType).getQuantity();
@@ -1881,16 +1889,6 @@ static bool interp__builtin_memcmp(InterpState &S, CodePtr OpPC,
18811889
bool IsWide =
18821890
(ID == Builtin::BIwmemcmp || ID == Builtin::BI__builtin_wmemcmp);
18831891

1884-
auto getElemType = [](const Pointer &P) -> QualType {
1885-
const Descriptor *Desc = P.getFieldDesc();
1886-
QualType T = Desc->getType();
1887-
if (T->isPointerType())
1888-
return T->getAs<PointerType>()->getPointeeType();
1889-
if (Desc->isArray())
1890-
return Desc->getElemQualType();
1891-
return T;
1892-
};
1893-
18941892
const ASTContext &ASTCtx = S.getASTContext();
18951893
QualType ElemTypeA = getElemType(PtrA);
18961894
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)