Skip to content

Commit 0a9c08c

Browse files
authored
[Clang] Implement P2280R4 Using unknown pointers and references in constant expressions (#95474)
P2280R4 allows the use of references in pointers of unknown origins in a constant expression context but only in specific cases that could be constant expressions. We track whether a variable is a constexpr unknown in a constant expression by setting a flag in either APValue or LValue and using this flag to prevent using unknown values in places where it is not allowed. Fixes: #63139 #63117
1 parent 19a7fe0 commit 0a9c08c

File tree

8 files changed

+344
-37
lines changed

8 files changed

+344
-37
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -318,6 +318,8 @@ C++23 Feature Support
318318

319319
- ``__cpp_explicit_this_parameter`` is now defined. (#GH82780)
320320

321+
- Add support for `P2280R4 Using unknown pointers and references in constant expressions <https://wg21.link/P2280R4>`_. (#GH63139)
322+
321323
C++20 Feature Support
322324
^^^^^^^^^^^^^^^^^^^^^
323325

clang/include/clang/AST/APValue.h

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -247,13 +247,15 @@ class APValue {
247247
struct NoLValuePath {};
248248
struct UninitArray {};
249249
struct UninitStruct {};
250+
struct ConstexprUnknown {};
250251

251252
template <typename Impl> friend class clang::serialization::BasicReaderBase;
252253
friend class ASTImporter;
253254
friend class ASTNodeImporter;
254255

255256
private:
256257
ValueKind Kind;
258+
bool AllowConstexprUnknown : 1;
257259

258260
struct ComplexAPSInt {
259261
APSInt Real, Imag;
@@ -312,32 +314,39 @@ class APValue {
312314
DataType Data;
313315

314316
public:
317+
bool allowConstexprUnknown() const { return AllowConstexprUnknown; }
318+
319+
void setConstexprUnknown(bool IsConstexprUnknown = true) {
320+
AllowConstexprUnknown = IsConstexprUnknown;
321+
}
322+
315323
/// Creates an empty APValue of type None.
316-
APValue() : Kind(None) {}
324+
APValue() : Kind(None), AllowConstexprUnknown(false) {}
317325
/// Creates an integer APValue holding the given value.
318-
explicit APValue(APSInt I) : Kind(None) {
326+
explicit APValue(APSInt I) : Kind(None), AllowConstexprUnknown(false) {
319327
MakeInt(); setInt(std::move(I));
320328
}
321329
/// Creates a float APValue holding the given value.
322-
explicit APValue(APFloat F) : Kind(None) {
330+
explicit APValue(APFloat F) : Kind(None), AllowConstexprUnknown(false) {
323331
MakeFloat(); setFloat(std::move(F));
324332
}
325333
/// Creates a fixed-point APValue holding the given value.
326-
explicit APValue(APFixedPoint FX) : Kind(None) {
334+
explicit APValue(APFixedPoint FX) : Kind(None), AllowConstexprUnknown(false) {
327335
MakeFixedPoint(std::move(FX));
328336
}
329337
/// Creates a vector APValue with \p N elements. The elements
330338
/// are read from \p E.
331-
explicit APValue(const APValue *E, unsigned N) : Kind(None) {
339+
explicit APValue(const APValue *E, unsigned N)
340+
: Kind(None), AllowConstexprUnknown(false) {
332341
MakeVector(); setVector(E, N);
333342
}
334343
/// Creates an integer complex APValue with the given real and imaginary
335344
/// values.
336-
APValue(APSInt R, APSInt I) : Kind(None) {
345+
APValue(APSInt R, APSInt I) : Kind(None), AllowConstexprUnknown(false) {
337346
MakeComplexInt(); setComplexInt(std::move(R), std::move(I));
338347
}
339348
/// Creates a float complex APValue with the given real and imaginary values.
340-
APValue(APFloat R, APFloat I) : Kind(None) {
349+
APValue(APFloat R, APFloat I) : Kind(None), AllowConstexprUnknown(false) {
341350
MakeComplexFloat(); setComplexFloat(std::move(R), std::move(I));
342351
}
343352
APValue(const APValue &RHS);
@@ -348,7 +357,7 @@ class APValue {
348357
/// \param IsNullPtr Whether this lvalue is a null pointer.
349358
APValue(LValueBase Base, const CharUnits &Offset, NoLValuePath,
350359
bool IsNullPtr = false)
351-
: Kind(None) {
360+
: Kind(None), AllowConstexprUnknown(false) {
352361
MakeLValue();
353362
setLValue(Base, Offset, NoLValuePath{}, IsNullPtr);
354363
}
@@ -362,31 +371,44 @@ class APValue {
362371
APValue(LValueBase Base, const CharUnits &Offset,
363372
ArrayRef<LValuePathEntry> Path, bool OnePastTheEnd,
364373
bool IsNullPtr = false)
365-
: Kind(None) {
374+
: Kind(None), AllowConstexprUnknown(false) {
366375
MakeLValue();
367376
setLValue(Base, Offset, Path, OnePastTheEnd, IsNullPtr);
368377
}
378+
/// Creates a constexpr unknown lvalue APValue.
379+
/// \param Base The base of the lvalue.
380+
/// \param Offset The offset of the lvalue.
381+
/// \param IsNullPtr Whether this lvalue is a null pointer.
382+
APValue(LValueBase Base, const CharUnits &Offset, ConstexprUnknown,
383+
bool IsNullPtr = false)
384+
: Kind(None), AllowConstexprUnknown(true) {
385+
MakeLValue();
386+
setLValue(Base, Offset, NoLValuePath{}, IsNullPtr);
387+
}
388+
369389
/// Creates a new array APValue.
370390
/// \param UninitArray Marker. Pass an empty UninitArray.
371391
/// \param InitElts Number of elements you're going to initialize in the
372392
/// array.
373393
/// \param Size Full size of the array.
374-
APValue(UninitArray, unsigned InitElts, unsigned Size) : Kind(None) {
394+
APValue(UninitArray, unsigned InitElts, unsigned Size)
395+
: Kind(None), AllowConstexprUnknown(false) {
375396
MakeArray(InitElts, Size);
376397
}
377398
/// Creates a new struct APValue.
378399
/// \param UninitStruct Marker. Pass an empty UninitStruct.
379400
/// \param NumBases Number of bases.
380401
/// \param NumMembers Number of members.
381-
APValue(UninitStruct, unsigned NumBases, unsigned NumMembers) : Kind(None) {
402+
APValue(UninitStruct, unsigned NumBases, unsigned NumMembers)
403+
: Kind(None), AllowConstexprUnknown(false) {
382404
MakeStruct(NumBases, NumMembers);
383405
}
384406
/// Creates a new union APValue.
385407
/// \param ActiveDecl The FieldDecl of the active union member.
386408
/// \param ActiveValue The value of the active union member.
387409
explicit APValue(const FieldDecl *ActiveDecl,
388410
const APValue &ActiveValue = APValue())
389-
: Kind(None) {
411+
: Kind(None), AllowConstexprUnknown(false) {
390412
MakeUnion();
391413
setUnion(ActiveDecl, ActiveValue);
392414
}
@@ -395,14 +417,15 @@ class APValue {
395417
/// \param IsDerivedMember Whether member is a derived one.
396418
/// \param Path The path of the member.
397419
APValue(const ValueDecl *Member, bool IsDerivedMember,
398-
ArrayRef<const CXXRecordDecl*> Path) : Kind(None) {
420+
ArrayRef<const CXXRecordDecl *> Path)
421+
: Kind(None), AllowConstexprUnknown(false) {
399422
MakeMemberPointer(Member, IsDerivedMember, Path);
400423
}
401424
/// Creates a new address label diff APValue.
402425
/// \param LHSExpr The left-hand side of the difference.
403426
/// \param RHSExpr The right-hand side of the difference.
404-
APValue(const AddrLabelExpr* LHSExpr, const AddrLabelExpr* RHSExpr)
405-
: Kind(None) {
427+
APValue(const AddrLabelExpr *LHSExpr, const AddrLabelExpr *RHSExpr)
428+
: Kind(None), AllowConstexprUnknown(false) {
406429
MakeAddrLabelDiff(); setAddrLabelDiff(LHSExpr, RHSExpr);
407430
}
408431
static APValue IndeterminateValue() {

clang/lib/AST/APValue.cpp

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -308,7 +308,8 @@ APValue::UnionData::~UnionData () {
308308
delete Value;
309309
}
310310

311-
APValue::APValue(const APValue &RHS) : Kind(None) {
311+
APValue::APValue(const APValue &RHS)
312+
: Kind(None), AllowConstexprUnknown(RHS.AllowConstexprUnknown) {
312313
switch (RHS.getKind()) {
313314
case None:
314315
case Indeterminate:
@@ -379,13 +380,17 @@ APValue::APValue(const APValue &RHS) : Kind(None) {
379380
}
380381
}
381382

382-
APValue::APValue(APValue &&RHS) : Kind(RHS.Kind), Data(RHS.Data) {
383+
APValue::APValue(APValue &&RHS)
384+
: Kind(RHS.Kind), AllowConstexprUnknown(RHS.AllowConstexprUnknown),
385+
Data(RHS.Data) {
383386
RHS.Kind = None;
384387
}
385388

386389
APValue &APValue::operator=(const APValue &RHS) {
387390
if (this != &RHS)
388391
*this = APValue(RHS);
392+
393+
AllowConstexprUnknown = RHS.AllowConstexprUnknown;
389394
return *this;
390395
}
391396

@@ -395,6 +400,7 @@ APValue &APValue::operator=(APValue &&RHS) {
395400
DestroyDataAndMakeUninit();
396401
Kind = RHS.Kind;
397402
Data = RHS.Data;
403+
AllowConstexprUnknown = RHS.AllowConstexprUnknown;
398404
RHS.Kind = None;
399405
}
400406
return *this;
@@ -426,6 +432,7 @@ void APValue::DestroyDataAndMakeUninit() {
426432
else if (Kind == AddrLabelDiff)
427433
((AddrLabelDiffData *)(char *)&Data)->~AddrLabelDiffData();
428434
Kind = None;
435+
AllowConstexprUnknown = false;
429436
}
430437

431438
bool APValue::needsCleanup() const {
@@ -468,6 +475,10 @@ bool APValue::needsCleanup() const {
468475
void APValue::swap(APValue &RHS) {
469476
std::swap(Kind, RHS.Kind);
470477
std::swap(Data, RHS.Data);
478+
// We can't use std::swap w/ bit-fields
479+
bool tmp = AllowConstexprUnknown;
480+
AllowConstexprUnknown = RHS.AllowConstexprUnknown;
481+
RHS.AllowConstexprUnknown = tmp;
471482
}
472483

473484
/// Profile the value of an APInt, excluding its bit-width.

0 commit comments

Comments
 (0)