Skip to content

Commit 5b48e38

Browse files
author
git apple-llvm automerger
committed
Merge commit '9e5470e7d6ea' from llvm.org/main into next
2 parents 7b2fbd5 + 9e5470e commit 5b48e38

File tree

16 files changed

+238
-46
lines changed

16 files changed

+238
-46
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -674,7 +674,7 @@ Improvements to Clang's diagnostics
674674
#GH142457, #GH139913, #GH138850, #GH137867, #GH137860, #GH107840, #GH93308,
675675
#GH69470, #GH59391, #GH58172, #GH46215, #GH45915, #GH45891, #GH44490,
676676
#GH36703, #GH32903, #GH23312, #GH69874.
677-
677+
678678
- Clang no longer emits a spurious -Wdangling-gsl warning in C++23 when
679679
iterating over an element of a temporary container in a range-based
680680
for loop.(#GH109793, #GH145164)
@@ -970,6 +970,7 @@ Bug Fixes to C++ Support
970970
- Fixed a crash involving list-initialization of an empty class with a
971971
non-empty initializer list. (#GH147949)
972972
- Fixed constant evaluation of equality comparisons of constexpr-unknown references. (#GH147663)
973+
- Diagnose binding a reference to ``*nullptr`` during constant evaluation. (#GH48665)
973974

974975
Bug Fixes to AST Handling
975976
^^^^^^^^^^^^^^^^^^^^^^^^^

clang/include/clang/Basic/DiagnosticASTKinds.td

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,11 @@ def note_constexpr_heap_alloc_limit_exceeded : Note<
174174
def note_constexpr_this : Note<
175175
"%select{|implicit }0use of 'this' pointer is only allowed within the "
176176
"evaluation of a call to a 'constexpr' member function">;
177-
def access_kind : TextSubstitution<
178-
"%select{read of|read of|assignment to|increment of|decrement of|"
179-
"member call on|dynamic_cast of|typeid applied to|construction of|"
180-
"destruction of|read of}0">;
177+
def access_kind
178+
: TextSubstitution<
179+
"%select{read of|read of|assignment to|increment of|decrement of|"
180+
"member call on|dynamic_cast of|typeid applied to|construction of|"
181+
"destruction of|read of|read of}0">;
181182
def access_kind_subobject : TextSubstitution<
182183
"%select{read of|read of|assignment to|increment of|decrement of|"
183184
"member call on|dynamic_cast of|typeid applied to|"
@@ -222,6 +223,9 @@ def note_constexpr_ltor_incomplete_type : Note<
222223
def note_constexpr_access_null : Note<
223224
"%sub{access_kind}0 "
224225
"dereferenced null pointer is not allowed in a constant expression">;
226+
def note_constexpr_dereferencing_null
227+
: Note<"dereferencing a null pointer is not allowed in a constant "
228+
"expression">;
225229
def note_constexpr_access_past_end : Note<
226230
"%sub{access_kind}0 dereferenced one-past-the-end pointer "
227231
"is not allowed in a constant expression">;

clang/lib/AST/ByteCode/State.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ enum AccessKinds {
3535
AK_Construct,
3636
AK_Destroy,
3737
AK_IsWithinLifetime,
38+
AK_Dereference
3839
};
3940

4041
/// The order of this enum is important for diagnostics.

clang/lib/AST/ExprConstant.cpp

Lines changed: 85 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1574,7 +1574,7 @@ CallStackFrame::~CallStackFrame() {
15741574

15751575
static bool isRead(AccessKinds AK) {
15761576
return AK == AK_Read || AK == AK_ReadObjectRepresentation ||
1577-
AK == AK_IsWithinLifetime;
1577+
AK == AK_IsWithinLifetime || AK == AK_Dereference;
15781578
}
15791579

15801580
static bool isModification(AccessKinds AK) {
@@ -1585,6 +1585,7 @@ static bool isModification(AccessKinds AK) {
15851585
case AK_DynamicCast:
15861586
case AK_TypeId:
15871587
case AK_IsWithinLifetime:
1588+
case AK_Dereference:
15881589
return false;
15891590
case AK_Assign:
15901591
case AK_Increment:
@@ -1603,15 +1604,16 @@ static bool isAnyAccess(AccessKinds AK) {
16031604
/// Is this an access per the C++ definition?
16041605
static bool isFormalAccess(AccessKinds AK) {
16051606
return isAnyAccess(AK) && AK != AK_Construct && AK != AK_Destroy &&
1606-
AK != AK_IsWithinLifetime;
1607+
AK != AK_IsWithinLifetime && AK != AK_Dereference;
16071608
}
16081609

1609-
/// Is this kind of axcess valid on an indeterminate object value?
1610+
/// Is this kind of access valid on an indeterminate object value?
16101611
static bool isValidIndeterminateAccess(AccessKinds AK) {
16111612
switch (AK) {
16121613
case AK_Read:
16131614
case AK_Increment:
16141615
case AK_Decrement:
1616+
case AK_Dereference:
16151617
// These need the object's value.
16161618
return false;
16171619

@@ -1831,7 +1833,10 @@ namespace {
18311833
bool checkNullPointerForFoldAccess(EvalInfo &Info, const Expr *E,
18321834
AccessKinds AK) {
18331835
return checkNullPointerDiagnosingWith([&Info, E, AK] {
1834-
Info.FFDiag(E, diag::note_constexpr_access_null) << AK;
1836+
if (AK == AccessKinds::AK_Dereference)
1837+
Info.FFDiag(E, diag::note_constexpr_dereferencing_null);
1838+
else
1839+
Info.FFDiag(E, diag::note_constexpr_access_null) << AK;
18351840
});
18361841
}
18371842

@@ -4482,7 +4487,10 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
44824487
}
44834488

44844489
if (!LVal.Base) {
4485-
Info.FFDiag(E, diag::note_constexpr_access_null) << AK;
4490+
if (AK == AccessKinds::AK_Dereference)
4491+
Info.FFDiag(E, diag::note_constexpr_dereferencing_null);
4492+
else
4493+
Info.FFDiag(E, diag::note_constexpr_access_null) << AK;
44864494
return CompleteObject();
44874495
}
44884496

@@ -4584,8 +4592,9 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
45844592
ConstexprVar = VD->isConstexpr();
45854593

45864594
// Unless we're looking at a local variable or argument in a constexpr call,
4587-
// the variable we're reading must be const.
4588-
if (!Frame) {
4595+
// the variable we're reading must be const (unless we are binding to a
4596+
// reference).
4597+
if (AK != clang::AK_Dereference && !Frame) {
45894598
if (IsAccess && isa<ParmVarDecl>(VD)) {
45904599
// Access of a parameter that's not associated with a frame isn't going
45914600
// to work out, but we can leave it to evaluateVarDeclInit to provide a
@@ -4649,12 +4658,16 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
46494658
}
46504659
}
46514660

4652-
if (!evaluateVarDeclInit(Info, E, VD, Frame, LVal.getLValueVersion(), BaseVal))
4661+
// When binding to a reference, the variable does not need to be constexpr
4662+
// or have constant initalization.
4663+
if (AK != clang::AK_Dereference &&
4664+
!evaluateVarDeclInit(Info, E, VD, Frame, LVal.getLValueVersion(),
4665+
BaseVal))
46534666
return CompleteObject();
46544667
// If evaluateVarDeclInit sees a constexpr-unknown variable, it returns
46554668
// a null BaseVal. Any constexpr-unknown variable seen here is an error:
46564669
// we can't access a constexpr-unknown object.
4657-
if (!BaseVal) {
4670+
if (AK != clang::AK_Dereference && !BaseVal) {
46584671
Info.FFDiag(E, diag::note_constexpr_access_unknown_variable, 1)
46594672
<< AK << VD;
46604673
Info.Note(VD->getLocation(), diag::note_declared_at);
@@ -4668,7 +4681,10 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
46684681
}
46694682
return CompleteObject(LVal.Base, &(*Alloc)->Value,
46704683
LVal.Base.getDynamicAllocType());
4671-
} else {
4684+
}
4685+
// When binding to a reference, the variable does not need to be
4686+
// within its lifetime.
4687+
else if (AK != clang::AK_Dereference) {
46724688
const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
46734689

46744690
if (!Frame) {
@@ -4749,7 +4765,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
47494765
NoteLValueLocation(Info, LVal.Base);
47504766
return CompleteObject();
47514767
}
4752-
} else {
4768+
} else if (AK != clang::AK_Dereference) {
47534769
BaseVal = Frame->getTemporary(Base, LVal.Base.getVersion());
47544770
assert(BaseVal && "missing value for temporary");
47554771
}
@@ -5377,6 +5393,29 @@ enum EvalStmtResult {
53775393
ESR_CaseNotFound
53785394
};
53795395
}
5396+
/// Evaluates the initializer of a reference.
5397+
static bool EvaluateInitForDeclOfReferenceType(EvalInfo &Info,
5398+
const ValueDecl *D,
5399+
const Expr *Init, LValue &Result,
5400+
APValue &Val) {
5401+
assert(Init->isGLValue() && D->getType()->isReferenceType());
5402+
// A reference is an lvalue.
5403+
if (!EvaluateLValue(Init, Result, Info))
5404+
return false;
5405+
// [C++26][decl.ref]
5406+
// The object designated by such a glvalue can be outside its lifetime
5407+
// Because a null pointer value or a pointer past the end of an object
5408+
// does not point to an object, a reference in a well-defined program cannot
5409+
// refer to such things;
5410+
if (!Result.Designator.Invalid && Result.Designator.isOnePastTheEnd()) {
5411+
Info.FFDiag(Init, diag::note_constexpr_access_past_end) << AK_Dereference;
5412+
return false;
5413+
}
5414+
5415+
// Save the result.
5416+
Result.moveInto(Val);
5417+
return true;
5418+
}
53805419

53815420
static bool EvaluateVarDecl(EvalInfo &Info, const VarDecl *VD) {
53825421
if (VD->isInvalidDecl())
@@ -5398,7 +5437,11 @@ static bool EvaluateVarDecl(EvalInfo &Info, const VarDecl *VD) {
53985437
if (InitE->isValueDependent())
53995438
return false;
54005439

5401-
if (!EvaluateInPlace(Val, Info, Result, InitE)) {
5440+
// For references to objects, check they do not designate a one-past-the-end
5441+
// object.
5442+
if (VD->getType()->isReferenceType()) {
5443+
return EvaluateInitForDeclOfReferenceType(Info, VD, InitE, Result, Val);
5444+
} else if (!EvaluateInPlace(Val, Info, Result, InitE)) {
54025445
// Wipe out any partially-computed value, to allow tracking that this
54035446
// evaluation failed.
54045447
Val = APValue();
@@ -7028,9 +7071,18 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
70287071
ThisOverrideRAII ThisOverride(*Info.CurrentCall, &SubobjectParent,
70297072
isa<CXXDefaultInitExpr>(Init));
70307073
FullExpressionRAII InitScope(Info);
7031-
if (!EvaluateInPlace(*Value, Info, Subobject, Init) ||
7032-
(FD && FD->isBitField() &&
7033-
!truncateBitfieldValue(Info, Init, *Value, FD))) {
7074+
if (FD && FD->getType()->isReferenceType() &&
7075+
!FD->getType()->isFunctionReferenceType()) {
7076+
LValue Result;
7077+
if (!EvaluateInitForDeclOfReferenceType(Info, FD, Init, Result,
7078+
*Value)) {
7079+
if (!Info.noteFailure())
7080+
return false;
7081+
Success = false;
7082+
}
7083+
} else if (!EvaluateInPlace(*Value, Info, Subobject, Init) ||
7084+
(FD && FD->isBitField() &&
7085+
!truncateBitfieldValue(Info, Init, *Value, FD))) {
70347086
// If we're checking for a potential constant expression, evaluate all
70357087
// initializers even if some of them fail.
70367088
if (!Info.noteFailure())
@@ -9495,7 +9547,13 @@ bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
94959547
}
94969548

94979549
bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) {
9498-
return evaluatePointer(E->getSubExpr(), Result);
9550+
bool Success = evaluatePointer(E->getSubExpr(), Result);
9551+
// [C++26][expr.unary.op]
9552+
// If the operand points to an object or function, the result
9553+
// denotes that object or function; otherwise, the behavior is undefined.
9554+
return Success &&
9555+
(!E->getType().getNonReferenceType()->isObjectType() ||
9556+
findCompleteObject(Info, E, AK_Dereference, Result, E->getType()));
94999557
}
95009558

95019559
bool LValueExprEvaluator::VisitUnaryReal(const UnaryOperator *E) {
@@ -11320,9 +11378,17 @@ bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr(
1132011378
isa<CXXDefaultInitExpr>(Init));
1132111379

1132211380
APValue &FieldVal = Result.getStructField(Field->getFieldIndex());
11323-
if (!EvaluateInPlace(FieldVal, Info, Subobject, Init) ||
11324-
(Field->isBitField() && !truncateBitfieldValue(Info, Init,
11325-
FieldVal, Field))) {
11381+
if (Field->getType()->isReferenceType()) {
11382+
LValue Result;
11383+
if (!EvaluateInitForDeclOfReferenceType(Info, Field, Init, Result,
11384+
FieldVal)) {
11385+
if (!Info.noteFailure())
11386+
return false;
11387+
Success = false;
11388+
}
11389+
} else if (!EvaluateInPlace(FieldVal, Info, Subobject, Init) ||
11390+
(Field->isBitField() &&
11391+
!truncateBitfieldValue(Info, Init, FieldVal, Field))) {
1132611392
if (!Info.noteFailure())
1132711393
return false;
1132811394
Success = false;

clang/test/AST/ByteCode/complex.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -396,10 +396,10 @@ namespace ComplexConstexpr {
396396
// both-note {{cannot refer to element 3 of array of 2 elements}}
397397
constexpr _Complex float *p = 0;
398398
constexpr float pr = __real *p; // both-error {{constant expr}} \
399-
// ref-note {{cannot access real component of null}} \
400-
// expected-note {{read of dereferenced null pointer}}
399+
// expected-note {{read of dereferenced null pointer}} \
400+
// ref-note {{dereferencing a null pointer}}
401401
constexpr float pi = __imag *p; // both-error {{constant expr}} \
402-
// ref-note {{cannot access imaginary component of null}}
402+
// ref-note {{dereferencing a null pointer}}
403403
constexpr const _Complex double *q = &test3 + 1;
404404
constexpr double qr = __real *q; // ref-error {{constant expr}} \
405405
// ref-note {{cannot access real component of pointer past the end}}

clang/test/AST/ByteCode/const-eval.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ struct s {
5151
};
5252

5353
EVAL_EXPR(19, ((int)&*(char*)10 == 10 ? 1 : -1));
54+
// ref-error@-1 {{expression is not an integer constant expression}} \
55+
// ref-note@-1 {{dereferencing a null pointer}}
5456

5557
#ifndef NEW_INTERP
5658
EVAL_EXPR(20, __builtin_constant_p(*((int*) 10)));

clang/test/AST/ByteCode/cxx11.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ struct S {
3939
constexpr S s = { 5 };
4040
constexpr const int *p = &s.m + 1;
4141

42-
constexpr const int *np2 = &(*(int(*)[4])nullptr)[0]; // ok
42+
constexpr const int *np2 = &(*(int(*)[4])nullptr)[0];
43+
// ref-error@-1 {{constexpr variable 'np2' must be initialized by a constant expression}} \
44+
// ref-note@-1 {{dereferencing a null pointer is not allowed in a constant expression}}
4345

4446
constexpr int preDec(int x) { // both-error {{never produces a constant expression}}
4547
return --x; // both-note {{subexpression}}

clang/test/AST/ByteCode/records.cpp

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -413,7 +413,7 @@ namespace DeriveFailures {
413413

414414
constexpr Derived(int i) : OtherVal(i) {} // ref-error {{never produces a constant expression}} \
415415
// both-note {{non-constexpr constructor 'Base' cannot be used in a constant expression}} \
416-
// ref-note {{non-constexpr constructor 'Base' cannot be used in a constant expression}}
416+
// ref-note {{non-constexpr constructor 'Base' cannot be used in a constant expression}}
417417
};
418418

419419
constexpr Derived D(12); // both-error {{must be initialized by a constant expression}} \
@@ -1660,9 +1660,11 @@ namespace NullptrCast {
16601660
constexpr A *na = nullptr;
16611661
constexpr B *nb = nullptr;
16621662
constexpr A &ra = *nb; // both-error {{constant expression}} \
1663-
// both-note {{cannot access base class of null pointer}}
1663+
// ref-note {{dereferencing a null pointer}} \
1664+
// expected-note {{cannot access base class of null pointer}}
16641665
constexpr B &rb = (B&)*na; // both-error {{constant expression}} \
1665-
// both-note {{cannot access derived class of null pointer}}
1666+
// ref-note {{dereferencing a null pointer}} \
1667+
// expected-note {{cannot access derived class of null pointer}}
16661668
constexpr bool test() {
16671669
auto a = (A*)(B*)nullptr;
16681670

@@ -1740,7 +1742,7 @@ namespace CtorOfInvalidClass {
17401742
#if __cplusplus >= 202002L
17411743
template <typename T, auto Q>
17421744
concept ReferenceOf = Q;
1743-
/// This calls a valid and constexpr copy constructor of InvalidCtor,
1745+
/// This calls a valid and constexpr copy constructor of InvalidCtor,
17441746
/// but should still be rejected.
17451747
template<ReferenceOf<InvalidCtor> auto R, typename Rep> int F; // both-error {{non-type template argument is not a constant expression}}
17461748
#endif

clang/test/CXX/drs/cwg14xx.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,8 @@ void f() {
107107
constexpr int p = &*a;
108108
// since-cxx11-error@-1 {{cannot initialize a variable of type 'const int' with an rvalue of type 'A *'}}
109109
constexpr A *p2 = &*a;
110+
// since-cxx11-error@-1 {{constexpr variable 'p2' must be initialized by a constant expression}}
111+
// since-cxx11-note@-2 {{dereferencing a null pointer}}
110112
}
111113

112114
struct A {

clang/test/CXX/expr/expr.const/p2-0x.cpp

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -199,15 +199,15 @@ namespace UndefinedBehavior {
199199

200200
constexpr A *na = nullptr;
201201
constexpr B *nb = nullptr;
202-
constexpr A &ra = *nb; // expected-error {{constant expression}} expected-note {{cannot access base class of null pointer}}
203-
constexpr B &rb = (B&)*na; // expected-error {{constant expression}} expected-note {{cannot access derived class of null pointer}}
202+
constexpr A &ra = *nb; // expected-error {{constant expression}} expected-note {{dereferencing a null pointer}}
203+
constexpr B &rb = (B&)*na; // expected-error {{constant expression}} expected-note {{dereferencing a null pointer}}
204204
static_assert((A*)nb == 0, "");
205205
static_assert((B*)na == 0, "");
206206
constexpr const int &nf = nb->n; // expected-error {{constant expression}} expected-note {{cannot access field of null pointer}}
207207
constexpr const int &mf = nb->m; // expected-error {{constant expression}} expected-note {{cannot access field of null pointer}}
208208
constexpr const int *np1 = (int*)nullptr + 0; // ok
209-
constexpr const int *np2 = &(*(int(*)[4])nullptr)[0]; // ok
210-
constexpr const int *np3 = &(*(int(*)[4])nullptr)[2]; // expected-error {{constant expression}} expected-note {{cannot perform pointer arithmetic on null pointer}}
209+
constexpr const int *np2 = &(*(int(*)[4])nullptr)[0]; // expected-error {{constant expression}} expected-note {{dereferencing a null pointer}}
210+
constexpr const int *np3 = &(*(int(*)[4])nullptr)[2]; // expected-error {{constant expression}} expected-note {{dereferencing a null pointer}}
211211

212212
struct C {
213213
constexpr int f() const { return 0; }
@@ -485,7 +485,7 @@ namespace std {
485485
namespace TypeId {
486486
struct S { virtual void f(); };
487487
constexpr S *p = 0;
488-
constexpr const std::type_info &ti1 = typeid(*p); // expected-error {{must be initialized by a constant expression}} cxx11-note {{typeid applied to expression of polymorphic type 'S'}} cxx20-note {{dereferenced null pointer}}
488+
constexpr const std::type_info &ti1 = typeid(*p); // expected-error {{must be initialized by a constant expression}} cxx11-note {{typeid applied to expression of polymorphic type 'S'}} cxx20-note {{dereferencing a null pointer}}
489489

490490
struct T {} t;
491491
constexpr const std::type_info &ti2 = typeid(t);

0 commit comments

Comments
 (0)