[clang] [libcxx] [Clang] Diagnose forming references to nullptr (PR #143667)
Corentin Jabot via cfe-commits
cfe-commits at lists.llvm.org
Thu Jul 10 06:32:22 PDT 2025
https://github.com/cor3ntin updated https://github.com/llvm/llvm-project/pull/143667
>From b54f67ad5755bff3959369f8cd81022abd5dfe22 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Wed, 2 Jul 2025 15:55:41 +0200
Subject: [PATCH 1/4] Diagnose all dereferences of null pointers
---
clang/docs/ReleaseNotes.rst | 1 +
.../include/clang/Basic/DiagnosticASTKinds.td | 9 +-
clang/lib/AST/ByteCode/State.h | 1 +
clang/lib/AST/ExprConstant.cpp | 87 +++++++++++++++----
clang/test/AST/ByteCode/complex.cpp | 5 +-
clang/test/AST/ByteCode/const-eval.c | 2 +
clang/test/AST/ByteCode/cxx11.cpp | 4 +-
clang/test/AST/ByteCode/records.cpp | 10 ++-
clang/test/CXX/drs/cwg14xx.cpp | 2 +
clang/test/CXX/expr/expr.const/p2-0x.cpp | 8 +-
clang/test/Sema/const-eval.c | 5 +-
.../SemaCXX/constant-expression-cxx11.cpp | 4 +-
.../SemaCXX/constant-expression-cxx14.cpp | 56 +++++++++++-
.../SemaCXX/constant-expression-cxx2a.cpp | 2 +-
.../SemaCXX/constexpr-backtrace-limit.cpp | 4 +-
.../range.zip/iterator/increment.pass.cpp | 4 +-
16 files changed, 164 insertions(+), 40 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 3d893e0aa8e2c..60e7def16d6d2 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -896,6 +896,7 @@ Bug Fixes to C++ Support
- Fixed a crash when constant evaluating some explicit object member assignment operators. (#GH142835)
- Fixed an access checking bug when substituting into concepts (#GH115838)
- Fix a bug where private access specifier of overloaded function not respected. (#GH107629)
+- Diagnose binding a reference to ``*nullptr`` during constant evaluation. (#GH48665)
Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td
index e3be4ab47633d..7b27fa7e256a6 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -174,10 +174,11 @@ def note_constexpr_heap_alloc_limit_exceeded : Note<
def note_constexpr_this : Note<
"%select{|implicit }0use of 'this' pointer is only allowed within the "
"evaluation of a call to a 'constexpr' member function">;
-def access_kind : TextSubstitution<
- "%select{read of|read of|assignment to|increment of|decrement of|"
- "member call on|dynamic_cast of|typeid applied to|construction of|"
- "destruction of|read of}0">;
+def access_kind
+ : TextSubstitution<
+ "%select{read of|read of|assignment to|increment of|decrement of|"
+ "member call on|dynamic_cast of|typeid applied to|construction of|"
+ "destruction of|read of|read of}0">;
def access_kind_subobject : TextSubstitution<
"%select{read of|read of|assignment to|increment of|decrement of|"
"member call on|dynamic_cast of|typeid applied to|"
diff --git a/clang/lib/AST/ByteCode/State.h b/clang/lib/AST/ByteCode/State.h
index 9a81fa6b7d220..6fc33222ac956 100644
--- a/clang/lib/AST/ByteCode/State.h
+++ b/clang/lib/AST/ByteCode/State.h
@@ -35,6 +35,7 @@ enum AccessKinds {
AK_Construct,
AK_Destroy,
AK_IsWithinLifetime,
+ AK_Dereference
};
/// The order of this enum is important for diagnostics.
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index bf9208763b1ab..7b79f2bec1dea 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -1529,7 +1529,7 @@ CallStackFrame::~CallStackFrame() {
static bool isRead(AccessKinds AK) {
return AK == AK_Read || AK == AK_ReadObjectRepresentation ||
- AK == AK_IsWithinLifetime;
+ AK == AK_IsWithinLifetime || AK == AK_Dereference;
}
static bool isModification(AccessKinds AK) {
@@ -1540,6 +1540,7 @@ static bool isModification(AccessKinds AK) {
case AK_DynamicCast:
case AK_TypeId:
case AK_IsWithinLifetime:
+ case AK_Dereference:
return false;
case AK_Assign:
case AK_Increment:
@@ -1558,7 +1559,7 @@ static bool isAnyAccess(AccessKinds AK) {
/// Is this an access per the C++ definition?
static bool isFormalAccess(AccessKinds AK) {
return isAnyAccess(AK) && AK != AK_Construct && AK != AK_Destroy &&
- AK != AK_IsWithinLifetime;
+ AK != AK_IsWithinLifetime && AK != AK_Dereference;
}
/// Is this kind of axcess valid on an indeterminate object value?
@@ -1571,6 +1572,7 @@ static bool isValidIndeterminateAccess(AccessKinds AK) {
return false;
case AK_IsWithinLifetime:
+ case AK_Dereference:
case AK_ReadObjectRepresentation:
case AK_Assign:
case AK_Construct:
@@ -4424,8 +4426,9 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
ConstexprVar = VD->isConstexpr();
// Unless we're looking at a local variable or argument in a constexpr call,
- // the variable we're reading must be const.
- if (!Frame) {
+ // the variable we're reading must be const (unless we are binding to a
+ // reference).
+ if (AK != clang::AK_Dereference && !Frame) {
if (IsAccess && isa<ParmVarDecl>(VD)) {
// Access of a parameter that's not associated with a frame isn't going
// to work out, but we can leave it to evaluateVarDeclInit to provide a
@@ -4489,7 +4492,11 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
}
}
- if (!evaluateVarDeclInit(Info, E, VD, Frame, LVal.getLValueVersion(), BaseVal))
+ // When binding to a reference, the variable does not need to be constexpr
+ // or have constant initalization.
+ if (AK != clang::AK_Dereference &&
+ !evaluateVarDeclInit(Info, E, VD, Frame, LVal.getLValueVersion(),
+ BaseVal))
return CompleteObject();
} else if (DynamicAllocLValue DA = LVal.Base.dyn_cast<DynamicAllocLValue>()) {
std::optional<DynAlloc *> Alloc = Info.lookupDynamicAlloc(DA);
@@ -4499,7 +4506,10 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
}
return CompleteObject(LVal.Base, &(*Alloc)->Value,
LVal.Base.getDynamicAllocType());
- } else {
+ }
+ // When binding to a reference, the variable does not need to be
+ // within its lifetime.
+ else if (AK != clang::AK_Dereference) {
const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
if (!Frame) {
@@ -4556,7 +4566,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
NoteLValueLocation(Info, LVal.Base);
return CompleteObject();
}
- } else {
+ } else if (AK != clang::AK_Dereference) {
BaseVal = Frame->getTemporary(Base, LVal.Base.getVersion());
assert(BaseVal && "missing value for temporary");
}
@@ -5221,6 +5231,29 @@ enum EvalStmtResult {
ESR_CaseNotFound
};
}
+/// Evaluates the initializer of a reference.
+static bool EvaluateInitForDeclOfReferenceType(EvalInfo &Info,
+ const ValueDecl *D,
+ const Expr *Init, LValue &Result,
+ APValue &Val) {
+ assert(Init->isGLValue() && D->getType()->isReferenceType());
+ // A reference is an lvalue
+ if (!EvaluateLValue(Init, Result, Info))
+ return false;
+ // [C++26][decl.ref]
+ // The object designated by such a glvalue can be outside its lifetime
+ // Because a null pointer value or a pointer past the end of an object
+ // does not point to an object, a reference in a well-defined program cannot
+ // refer to such things;
+ if (!Result.Designator.Invalid && Result.Designator.isOnePastTheEnd()) {
+ Info.FFDiag(Init, diag::note_constexpr_access_past_end) << AK_Dereference;
+ return false;
+ }
+
+ // save the result
+ Result.moveInto(Val);
+ return true;
+}
static bool EvaluateVarDecl(EvalInfo &Info, const VarDecl *VD) {
if (VD->isInvalidDecl())
@@ -5242,7 +5275,10 @@ static bool EvaluateVarDecl(EvalInfo &Info, const VarDecl *VD) {
if (InitE->isValueDependent())
return false;
- if (!EvaluateInPlace(Val, Info, Result, InitE)) {
+ if (VD->getType()->isReferenceType() &&
+ !VD->getType()->isFunctionReferenceType()) {
+ return EvaluateInitForDeclOfReferenceType(Info, VD, InitE, Result, Val);
+ } else if (!EvaluateInPlace(Val, Info, Result, InitE)) {
// Wipe out any partially-computed value, to allow tracking that this
// evaluation failed.
Val = APValue();
@@ -6883,9 +6919,18 @@ static bool HandleConstructorCall(const Expr *E, const LValue &This,
ThisOverrideRAII ThisOverride(*Info.CurrentCall, &SubobjectParent,
isa<CXXDefaultInitExpr>(Init));
FullExpressionRAII InitScope(Info);
- if (!EvaluateInPlace(*Value, Info, Subobject, Init) ||
- (FD && FD->isBitField() &&
- !truncateBitfieldValue(Info, Init, *Value, FD))) {
+ if (FD && FD->getType()->isReferenceType() &&
+ !FD->getType()->isFunctionReferenceType()) {
+ LValue Result;
+ if (!EvaluateInitForDeclOfReferenceType(Info, FD, Init, Result,
+ *Value)) {
+ if (!Info.noteFailure())
+ return false;
+ Success = false;
+ }
+ } else if (!EvaluateInPlace(*Value, Info, Subobject, Init) ||
+ (FD && FD->isBitField() &&
+ !truncateBitfieldValue(Info, Init, *Value, FD))) {
// If we're checking for a potential constant expression, evaluate all
// initializers even if some of them fail.
if (!Info.noteFailure())
@@ -9293,7 +9338,10 @@ bool LValueExprEvaluator::VisitArraySubscriptExpr(const ArraySubscriptExpr *E) {
}
bool LValueExprEvaluator::VisitUnaryDeref(const UnaryOperator *E) {
- return evaluatePointer(E->getSubExpr(), Result);
+ bool Success = evaluatePointer(E->getSubExpr(), Result);
+ return Success &&
+ (!E->getType().getNonReferenceType()->isObjectType() ||
+ findCompleteObject(Info, E, AK_Dereference, Result, E->getType()));
}
bool LValueExprEvaluator::VisitUnaryReal(const UnaryOperator *E) {
@@ -10912,9 +10960,18 @@ bool RecordExprEvaluator::VisitCXXParenListOrInitListExpr(
isa<CXXDefaultInitExpr>(Init));
APValue &FieldVal = Result.getStructField(Field->getFieldIndex());
- if (!EvaluateInPlace(FieldVal, Info, Subobject, Init) ||
- (Field->isBitField() && !truncateBitfieldValue(Info, Init,
- FieldVal, Field))) {
+ if (Field->getType()->isReferenceType() &&
+ !Field->getType()->isFunctionReferenceType()) {
+ LValue Result;
+ if (!EvaluateInitForDeclOfReferenceType(Info, Field, Init, Result,
+ FieldVal)) {
+ if (!Info.noteFailure())
+ return false;
+ Success = false;
+ }
+ } else if (!EvaluateInPlace(FieldVal, Info, Subobject, Init) ||
+ (Field->isBitField() &&
+ !truncateBitfieldValue(Info, Init, FieldVal, Field))) {
if (!Info.noteFailure())
return false;
Success = false;
diff --git a/clang/test/AST/ByteCode/complex.cpp b/clang/test/AST/ByteCode/complex.cpp
index 2c0111c53d3bf..17f315b24eccb 100644
--- a/clang/test/AST/ByteCode/complex.cpp
+++ b/clang/test/AST/ByteCode/complex.cpp
@@ -396,10 +396,9 @@ namespace ComplexConstexpr {
// both-note {{cannot refer to element 3 of array of 2 elements}}
constexpr _Complex float *p = 0;
constexpr float pr = __real *p; // both-error {{constant expr}} \
- // ref-note {{cannot access real component of null}} \
- // expected-note {{read of dereferenced null pointer}}
+ // both-note {{read of dereferenced null pointer}}
constexpr float pi = __imag *p; // both-error {{constant expr}} \
- // ref-note {{cannot access imaginary component of null}}
+ // ref-note {{read of dereferenced null pointer}}
constexpr const _Complex double *q = &test3 + 1;
constexpr double qr = __real *q; // ref-error {{constant expr}} \
// ref-note {{cannot access real component of pointer past the end}}
diff --git a/clang/test/AST/ByteCode/const-eval.c b/clang/test/AST/ByteCode/const-eval.c
index eab14c08ec809..08f5f0adb3772 100644
--- a/clang/test/AST/ByteCode/const-eval.c
+++ b/clang/test/AST/ByteCode/const-eval.c
@@ -51,6 +51,8 @@ struct s {
};
EVAL_EXPR(19, ((int)&*(char*)10 == 10 ? 1 : -1));
+// ref-error at -1 {{expression is not an integer constant expression}} \
+// ref-note at -1 {{read of dereferenced null pointer is not allowed in a constant expression}}
#ifndef NEW_INTERP
EVAL_EXPR(20, __builtin_constant_p(*((int*) 10)));
diff --git a/clang/test/AST/ByteCode/cxx11.cpp b/clang/test/AST/ByteCode/cxx11.cpp
index b34e7823220e2..58924a5fc48d9 100644
--- a/clang/test/AST/ByteCode/cxx11.cpp
+++ b/clang/test/AST/ByteCode/cxx11.cpp
@@ -39,7 +39,9 @@ struct S {
constexpr S s = { 5 };
constexpr const int *p = &s.m + 1;
-constexpr const int *np2 = &(*(int(*)[4])nullptr)[0]; // ok
+constexpr const int *np2 = &(*(int(*)[4])nullptr)[0];
+// ref-error at -1 {{constexpr variable 'np2' must be initialized by a constant expression}} \
+// ref-note at -1 {{read of dereferenced null pointer is not allowed in a constant expression}}
constexpr int preDec(int x) { // both-error {{never produces a constant expression}}
return --x; // both-note {{subexpression}}
diff --git a/clang/test/AST/ByteCode/records.cpp b/clang/test/AST/ByteCode/records.cpp
index 9361d6ddeda70..41d66d8fce8d2 100644
--- a/clang/test/AST/ByteCode/records.cpp
+++ b/clang/test/AST/ByteCode/records.cpp
@@ -413,7 +413,7 @@ namespace DeriveFailures {
constexpr Derived(int i) : OtherVal(i) {} // ref-error {{never produces a constant expression}} \
// both-note {{non-constexpr constructor 'Base' cannot be used in a constant expression}} \
- // ref-note {{non-constexpr constructor 'Base' cannot be used in a constant expression}}
+ // ref-note {{non-constexpr constructor 'Base' cannot be used in a constant expression}}
};
constexpr Derived D(12); // both-error {{must be initialized by a constant expression}} \
@@ -1662,9 +1662,11 @@ namespace NullptrCast {
constexpr A *na = nullptr;
constexpr B *nb = nullptr;
constexpr A &ra = *nb; // both-error {{constant expression}} \
- // both-note {{cannot access base class of null pointer}}
+ // ref-note {{read of dereferenced null pointer}} \
+ // expected-note {{cannot access base class of null pointer}}
constexpr B &rb = (B&)*na; // both-error {{constant expression}} \
- // both-note {{cannot access derived class of null pointer}}
+ // ref-note {{read of dereferenced null pointer}} \
+ // expected-note {{cannot access derived class of null pointer}}
constexpr bool test() {
auto a = (A*)(B*)nullptr;
@@ -1742,7 +1744,7 @@ namespace CtorOfInvalidClass {
#if __cplusplus >= 202002L
template <typename T, auto Q>
concept ReferenceOf = Q;
- /// This calls a valid and constexpr copy constructor of InvalidCtor,
+ /// This calls a valid and constexpr copy constructor of InvalidCtor,
/// but should still be rejected.
template<ReferenceOf<InvalidCtor> auto R, typename Rep> int F; // both-error {{non-type template argument is not a constant expression}}
#endif
diff --git a/clang/test/CXX/drs/cwg14xx.cpp b/clang/test/CXX/drs/cwg14xx.cpp
index 17d5c2fc2e210..d1c4424ab5b7a 100644
--- a/clang/test/CXX/drs/cwg14xx.cpp
+++ b/clang/test/CXX/drs/cwg14xx.cpp
@@ -107,6 +107,8 @@ void f() {
constexpr int p = &*a;
// since-cxx11-error at -1 {{cannot initialize a variable of type 'const int' with an rvalue of type 'A *'}}
constexpr A *p2 = &*a;
+ // since-cxx11-error at -1 {{constexpr variable 'p2' must be initialized by a constant expression}} \
+ // since-cxx11-note at -1 {{read of dereferenced null pointer is not allowed in a constant expression}}
}
struct A {
diff --git a/clang/test/CXX/expr/expr.const/p2-0x.cpp b/clang/test/CXX/expr/expr.const/p2-0x.cpp
index c6c3381be5523..6309192162205 100644
--- a/clang/test/CXX/expr/expr.const/p2-0x.cpp
+++ b/clang/test/CXX/expr/expr.const/p2-0x.cpp
@@ -199,15 +199,15 @@ namespace UndefinedBehavior {
constexpr A *na = nullptr;
constexpr B *nb = nullptr;
- constexpr A &ra = *nb; // expected-error {{constant expression}} expected-note {{cannot access base class of null pointer}}
- constexpr B &rb = (B&)*na; // expected-error {{constant expression}} expected-note {{cannot access derived class of null pointer}}
+ constexpr A &ra = *nb; // expected-error {{constant expression}} expected-note {{read of dereferenced null pointer}}
+ constexpr B &rb = (B&)*na; // expected-error {{constant expression}} expected-note {{read of dereferenced null pointer}}
static_assert((A*)nb == 0, "");
static_assert((B*)na == 0, "");
constexpr const int &nf = nb->n; // expected-error {{constant expression}} expected-note {{cannot access field of null pointer}}
constexpr const int &mf = nb->m; // expected-error {{constant expression}} expected-note {{cannot access field of null pointer}}
constexpr const int *np1 = (int*)nullptr + 0; // ok
- constexpr const int *np2 = &(*(int(*)[4])nullptr)[0]; // ok
- constexpr const int *np3 = &(*(int(*)[4])nullptr)[2]; // expected-error {{constant expression}} expected-note {{cannot perform pointer arithmetic on null pointer}}
+ constexpr const int *np2 = &(*(int(*)[4])nullptr)[0]; // expected-error {{constant expression}} expected-note {{read of dereferenced null pointer}}
+ constexpr const int *np3 = &(*(int(*)[4])nullptr)[2]; // expected-error {{constant expression}} expected-note {{read of dereferenced null pointer is not allowed in a constant expression}}
struct C {
constexpr int f() const { return 0; }
diff --git a/clang/test/Sema/const-eval.c b/clang/test/Sema/const-eval.c
index e358aceaad5a4..f3df072710491 100644
--- a/clang/test/Sema/const-eval.c
+++ b/clang/test/Sema/const-eval.c
@@ -32,7 +32,7 @@ void f(void)
_Complex float g16 = (1.0f + 1.0fi);
// ?: in constant expressions.
-int g17[(3?:1) - 2];
+int g17[(3?:1) - 2];
EVAL_EXPR(18, ((int)((void*)10 + 10)) == 20 ? 1 : -1);
@@ -41,6 +41,9 @@ struct s {
};
EVAL_EXPR(19, ((int)&*(char*)10 == 10 ? 1 : -1));
+// expected-error at -1 {{not an integer constant expression}} \
+// expected-note at -1 {{read of dereferenced null pointer is not allowed in a constant expression}}
+
EVAL_EXPR(20, __builtin_constant_p(*((int*) 10)));
diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp
index ab4e50072f654..b6a848267afe3 100644
--- a/clang/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp
@@ -1413,8 +1413,8 @@ namespace ComplexConstexpr {
static_assert(t2p[2] == 0.0, ""); // expected-error {{constant expr}} expected-note {{one-past-the-end pointer}}
static_assert(t2p[3] == 0.0, ""); // expected-error {{constant expr}} expected-note {{cannot refer to element 3 of array of 2 elements}}
constexpr _Complex float *p = 0; // expected-warning {{'_Complex' is a C99 extension}}
- constexpr float pr = __real *p; // expected-error {{constant expr}} expected-note {{cannot access real component of null}}
- constexpr float pi = __imag *p; // expected-error {{constant expr}} expected-note {{cannot access imaginary component of null}}
+ constexpr float pr = __real *p; // expected-error {{constant expr}} expected-note {{read of dereferenced null pointer}}
+ constexpr float pi = __imag *p; // expected-error {{constant expr}} expected-note {{read of dereferenced null pointer}}
constexpr const _Complex double *q = &test3 + 1; // expected-warning {{'_Complex' is a C99 extension}}
constexpr double qr = __real *q; // expected-error {{constant expr}} expected-note {{cannot access real component of pointer past the end}}
constexpr double qi = __imag *q; // expected-error {{constant expr}} expected-note {{cannot access imaginary component of pointer past the end}}
diff --git a/clang/test/SemaCXX/constant-expression-cxx14.cpp b/clang/test/SemaCXX/constant-expression-cxx14.cpp
index e16a69df3830d..3aa6384df42d0 100644
--- a/clang/test/SemaCXX/constant-expression-cxx14.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx14.cpp
@@ -265,7 +265,7 @@ namespace const_modify {
namespace null {
constexpr int test(int *p) {
- return *p = 123; // expected-note {{assignment to dereferenced null pointer}}
+ return *p = 123; // expected-note {{read of dereferenced null pointer}}
}
static_assert(test(0), ""); // expected-error {{constant expression}} expected-note {{in call}}
}
@@ -1321,3 +1321,57 @@ constexpr bool check = different_in_loop();
// expected-error at -1 {{}} expected-note at -1 {{in call}}
}
+
+namespace GH48665 {
+constexpr bool foo(int *i) {
+ int &j = *i;
+ // expected-note at -1 {{read of dereferenced null pointer}}
+ return true;
+}
+
+static_assert(foo(nullptr), ""); // expected-note {{in call to 'foo(nullptr)'}}
+// expected-error at -1 {{static assertion expression is not an integral constant expression}}
+
+constexpr bool foo_rvalue(int *i) {
+ int &&j = (int&&)*i;
+ // expected-note at -1 {{read of dereferenced null pointer}}
+ return true;
+}
+static_assert(foo_rvalue(nullptr), ""); // expected-note {{in call to 'foo_rvalue(nullptr)'}}
+// expected-error at -1 {{static assertion expression is not an integral constant expression}}
+
+int arr[3]; // expected-note {{declared here}}
+constexpr bool f() { // cxx14_20-error {{constexpr function never produces a constant expression}}
+ int &r = arr[3]; // expected-note {{read of dereferenced one-past-the-end pointer}} \
+ // cxx14_20-note {{read of dereferenced one-past-the-end pointer}} \
+ // expected-warning {{array index 3 is past the end of the array}}
+ return true;
+}
+static_assert(f(), ""); // expected-note {{in call to 'f()'}}
+// expected-error at -1 {{static assertion expression is not an integral constant expression}}
+
+
+struct Aggregate {
+ int &r;
+};
+constexpr bool test_agg(int *i) {
+ Aggregate a{*i}; //expected-note {{read of dereferenced null pointer}}
+ return true;
+}
+static_assert(test_agg(nullptr), ""); // expected-note {{in call to 'test_agg(nullptr)'}}
+// expected-error at -1 {{static assertion expression is not an integral constant expression}}
+
+struct B {
+ constexpr B(int *p) : r{*p} {} // expected-note {{read of dereferenced null pointer}}
+ int &r;
+};
+
+constexpr bool test_ctr(int *i) {
+ B b(i); // expected-note {{in call to 'B(nullptr)'}}
+ return true;
+}
+
+static_assert(test_ctr(nullptr), ""); // expected-note {{in call to 'test_ctr(nullptr)'}}
+// expected-error at -1 {{static assertion expression is not an integral constant expression}}
+
+}
diff --git a/clang/test/SemaCXX/constant-expression-cxx2a.cpp b/clang/test/SemaCXX/constant-expression-cxx2a.cpp
index 85720606fe9de..ffb7e633c2919 100644
--- a/clang/test/SemaCXX/constant-expression-cxx2a.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx2a.cpp
@@ -927,7 +927,7 @@ namespace dynamic_alloc {
constexpr void use_after_free() { // expected-error {{never produces a constant expression}}
int *p = new int;
delete p;
- *p = 1; // expected-note {{assignment to heap allocated object that has been deleted}}
+ *p = 1; // expected-note {{read of heap allocated object that has been deleted}}
}
constexpr void use_after_free_2() { // expected-error {{never produces a constant expression}}
struct X { constexpr void f() {} };
diff --git a/clang/test/SemaCXX/constexpr-backtrace-limit.cpp b/clang/test/SemaCXX/constexpr-backtrace-limit.cpp
index e867afdff5c3c..61991bf5d2931 100644
--- a/clang/test/SemaCXX/constexpr-backtrace-limit.cpp
+++ b/clang/test/SemaCXX/constexpr-backtrace-limit.cpp
@@ -15,14 +15,14 @@
// RUN: not %clang_cc1 -std=c++11 -fsyntax-only %s -fconstexpr-backtrace-limit=2 -fconstexpr-depth=8 -fno-caret-diagnostics 2>&1 | FileCheck %s -check-prefix=TEST3
// TEST3: constant expression
-// TEST3-NEXT: reinterpret_cast
+// TEST3-NEXT: read of dereferenced null pointe
// TEST3-NEXT: in call to 'recurse(0)'
// TEST3-NEXT: skipping 4 calls
// TEST3-NEXT: in call to 'recurse(5)'
// RUN: not %clang_cc1 -std=c++11 -fsyntax-only %s -fconstexpr-backtrace-limit=8 -fconstexpr-depth=8 -fno-caret-diagnostics 2>&1 | FileCheck %s -check-prefix=TEST4
// TEST4: constant expression
-// TEST4-NEXT: reinterpret_cast
+// TEST4-NEXT: read of dereferenced null pointe
// TEST4-NEXT: in call to 'recurse(0)'
// TEST4-NEXT: in call to 'recurse(1)'
// TEST4-NEXT: in call to 'recurse(2)'
diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/increment.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/increment.pass.cpp
index 0ca8d92800feb..94d2bd47e9806 100644
--- a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/increment.pass.cpp
+++ b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/increment.pass.cpp
@@ -59,7 +59,7 @@ constexpr bool test() {
{
// bidi
- int buffer[2] = {1, 2};
+ int buffer[3] = {1, 2, 3};
std::ranges::zip_view v(BidiCommonView{buffer});
auto it = v.begin();
@@ -81,7 +81,7 @@ constexpr bool test() {
{
// forward
- int buffer[2] = {1, 2};
+ int buffer[3] = {1, 2, 3};
std::ranges::zip_view v(ForwardSizedView{buffer});
auto it = v.begin();
>From b4fcf5c577442f9e6fa72b63e0805e68a84765d3 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Thu, 10 Jul 2025 14:13:37 +0200
Subject: [PATCH 2/4] address some feedback
---
clang/lib/AST/ExprConstant.cpp | 8 ++++----
clang/test/CXX/drs/cwg14xx.cpp | 4 ++--
2 files changed, 6 insertions(+), 6 deletions(-)
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 7b79f2bec1dea..e0e5eb46df9f3 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -1562,17 +1562,17 @@ static bool isFormalAccess(AccessKinds AK) {
AK != AK_IsWithinLifetime && AK != AK_Dereference;
}
-/// Is this kind of axcess valid on an indeterminate object value?
+/// Is this kind of access valid on an indeterminate object value?
static bool isValidIndeterminateAccess(AccessKinds AK) {
switch (AK) {
case AK_Read:
case AK_Increment:
case AK_Decrement:
+ case AK_Dereference:
// These need the object's value.
return false;
case AK_IsWithinLifetime:
- case AK_Dereference:
case AK_ReadObjectRepresentation:
case AK_Assign:
case AK_Construct:
@@ -5237,7 +5237,7 @@ static bool EvaluateInitForDeclOfReferenceType(EvalInfo &Info,
const Expr *Init, LValue &Result,
APValue &Val) {
assert(Init->isGLValue() && D->getType()->isReferenceType());
- // A reference is an lvalue
+ // A reference is an lvalue.
if (!EvaluateLValue(Init, Result, Info))
return false;
// [C++26][decl.ref]
@@ -5250,7 +5250,7 @@ static bool EvaluateInitForDeclOfReferenceType(EvalInfo &Info,
return false;
}
- // save the result
+ // Save the result.
Result.moveInto(Val);
return true;
}
diff --git a/clang/test/CXX/drs/cwg14xx.cpp b/clang/test/CXX/drs/cwg14xx.cpp
index d1c4424ab5b7a..2b036f2adb48e 100644
--- a/clang/test/CXX/drs/cwg14xx.cpp
+++ b/clang/test/CXX/drs/cwg14xx.cpp
@@ -107,8 +107,8 @@ void f() {
constexpr int p = &*a;
// since-cxx11-error at -1 {{cannot initialize a variable of type 'const int' with an rvalue of type 'A *'}}
constexpr A *p2 = &*a;
- // since-cxx11-error at -1 {{constexpr variable 'p2' must be initialized by a constant expression}} \
- // since-cxx11-note at -1 {{read of dereferenced null pointer is not allowed in a constant expression}}
+ // since-cxx11-error at -1 {{constexpr variable 'p2' must be initialized by a constant expression}}
+ // since-cxx11-note at -2 {{read of dereferenced null pointer is not allowed in a constant expression}}
}
struct A {
>From b8af65bef236b8f236701ad9e43f14e29e110de1 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Thu, 10 Jul 2025 14:35:13 +0200
Subject: [PATCH 3/4] Add a disting diagnostic for dereferencing a null pointer
> dereferencing a null pointer is not allowed in a constant expression
---
clang/include/clang/Basic/DiagnosticASTKinds.td | 2 ++
clang/lib/AST/ExprConstant.cpp | 10 ++++++++--
clang/test/AST/ByteCode/complex.cpp | 5 +++--
clang/test/AST/ByteCode/const-eval.c | 2 +-
clang/test/AST/ByteCode/cxx11.cpp | 2 +-
clang/test/AST/ByteCode/records.cpp | 4 ++--
clang/test/CXX/drs/cwg14xx.cpp | 2 +-
clang/test/CXX/expr/expr.const/p2-0x.cpp | 10 +++++-----
clang/test/Sema/const-eval.c | 2 +-
clang/test/SemaCXX/constant-expression-cxx11.cpp | 4 ++--
clang/test/SemaCXX/constant-expression-cxx14.cpp | 10 +++++-----
clang/test/SemaCXX/constexpr-backtrace-limit.cpp | 4 ++--
12 files changed, 33 insertions(+), 24 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td
index 7b27fa7e256a6..8d24bd1e86284 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -223,6 +223,8 @@ def note_constexpr_ltor_incomplete_type : Note<
def note_constexpr_access_null : Note<
"%sub{access_kind}0 "
"dereferenced null pointer is not allowed in a constant expression">;
+def note_constexpr_dereferencing_null : Note<
+ "dereferencing a null pointer is not allowed in a constant expression">;
def note_constexpr_access_past_end : Note<
"%sub{access_kind}0 dereferenced one-past-the-end pointer "
"is not allowed in a constant expression">;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index e0e5eb46df9f3..e65ba59c19839 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -1735,7 +1735,10 @@ namespace {
bool checkNullPointerForFoldAccess(EvalInfo &Info, const Expr *E,
AccessKinds AK) {
return checkNullPointerDiagnosingWith([&Info, E, AK] {
- Info.FFDiag(E, diag::note_constexpr_access_null) << AK;
+ if(AK == AccessKinds::AK_Dereference)
+ Info.FFDiag(E, diag::note_constexpr_dereferencing_null);
+ else
+ Info.FFDiag(E, diag::note_constexpr_access_null) << AK;
});
}
@@ -4324,7 +4327,10 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
}
if (!LVal.Base) {
- Info.FFDiag(E, diag::note_constexpr_access_null) << AK;
+ if(AK == AccessKinds::AK_Dereference)
+ Info.FFDiag(E, diag::note_constexpr_dereferencing_null);
+ else
+ Info.FFDiag(E, diag::note_constexpr_access_null) << AK;
return CompleteObject();
}
diff --git a/clang/test/AST/ByteCode/complex.cpp b/clang/test/AST/ByteCode/complex.cpp
index 17f315b24eccb..959d759005ef4 100644
--- a/clang/test/AST/ByteCode/complex.cpp
+++ b/clang/test/AST/ByteCode/complex.cpp
@@ -396,9 +396,10 @@ namespace ComplexConstexpr {
// both-note {{cannot refer to element 3 of array of 2 elements}}
constexpr _Complex float *p = 0;
constexpr float pr = __real *p; // both-error {{constant expr}} \
- // both-note {{read of dereferenced null pointer}}
+ // expected-note {{read of dereferenced null pointer}} \
+ // ref-note {{dereferencing a null pointer}}
constexpr float pi = __imag *p; // both-error {{constant expr}} \
- // ref-note {{read of dereferenced null pointer}}
+ // ref-note {{dereferencing a null pointer}}
constexpr const _Complex double *q = &test3 + 1;
constexpr double qr = __real *q; // ref-error {{constant expr}} \
// ref-note {{cannot access real component of pointer past the end}}
diff --git a/clang/test/AST/ByteCode/const-eval.c b/clang/test/AST/ByteCode/const-eval.c
index 08f5f0adb3772..c8651a744f969 100644
--- a/clang/test/AST/ByteCode/const-eval.c
+++ b/clang/test/AST/ByteCode/const-eval.c
@@ -52,7 +52,7 @@ struct s {
EVAL_EXPR(19, ((int)&*(char*)10 == 10 ? 1 : -1));
// ref-error at -1 {{expression is not an integer constant expression}} \
-// ref-note at -1 {{read of dereferenced null pointer is not allowed in a constant expression}}
+// ref-note at -1 {{dereferencing a null pointer}}
#ifndef NEW_INTERP
EVAL_EXPR(20, __builtin_constant_p(*((int*) 10)));
diff --git a/clang/test/AST/ByteCode/cxx11.cpp b/clang/test/AST/ByteCode/cxx11.cpp
index 58924a5fc48d9..55554220b0a8a 100644
--- a/clang/test/AST/ByteCode/cxx11.cpp
+++ b/clang/test/AST/ByteCode/cxx11.cpp
@@ -41,7 +41,7 @@ constexpr const int *p = &s.m + 1;
constexpr const int *np2 = &(*(int(*)[4])nullptr)[0];
// ref-error at -1 {{constexpr variable 'np2' must be initialized by a constant expression}} \
-// ref-note at -1 {{read of dereferenced null pointer is not allowed in a constant expression}}
+// ref-note at -1 {{dereferencing a null pointer is not allowed in a constant expression}}
constexpr int preDec(int x) { // both-error {{never produces a constant expression}}
return --x; // both-note {{subexpression}}
diff --git a/clang/test/AST/ByteCode/records.cpp b/clang/test/AST/ByteCode/records.cpp
index 41d66d8fce8d2..77db2221a34c7 100644
--- a/clang/test/AST/ByteCode/records.cpp
+++ b/clang/test/AST/ByteCode/records.cpp
@@ -1662,10 +1662,10 @@ namespace NullptrCast {
constexpr A *na = nullptr;
constexpr B *nb = nullptr;
constexpr A &ra = *nb; // both-error {{constant expression}} \
- // ref-note {{read of dereferenced null pointer}} \
+ // ref-note {{dereferencing a null pointer}} \
// expected-note {{cannot access base class of null pointer}}
constexpr B &rb = (B&)*na; // both-error {{constant expression}} \
- // ref-note {{read of dereferenced null pointer}} \
+ // ref-note {{dereferencing a null pointer}} \
// expected-note {{cannot access derived class of null pointer}}
constexpr bool test() {
auto a = (A*)(B*)nullptr;
diff --git a/clang/test/CXX/drs/cwg14xx.cpp b/clang/test/CXX/drs/cwg14xx.cpp
index 2b036f2adb48e..8d39018d8926c 100644
--- a/clang/test/CXX/drs/cwg14xx.cpp
+++ b/clang/test/CXX/drs/cwg14xx.cpp
@@ -108,7 +108,7 @@ void f() {
// since-cxx11-error at -1 {{cannot initialize a variable of type 'const int' with an rvalue of type 'A *'}}
constexpr A *p2 = &*a;
// since-cxx11-error at -1 {{constexpr variable 'p2' must be initialized by a constant expression}}
- // since-cxx11-note at -2 {{read of dereferenced null pointer is not allowed in a constant expression}}
+ // since-cxx11-note at -2 {{dereferencing a null pointer}}
}
struct A {
diff --git a/clang/test/CXX/expr/expr.const/p2-0x.cpp b/clang/test/CXX/expr/expr.const/p2-0x.cpp
index 6309192162205..910c8635f7353 100644
--- a/clang/test/CXX/expr/expr.const/p2-0x.cpp
+++ b/clang/test/CXX/expr/expr.const/p2-0x.cpp
@@ -199,15 +199,15 @@ namespace UndefinedBehavior {
constexpr A *na = nullptr;
constexpr B *nb = nullptr;
- constexpr A &ra = *nb; // expected-error {{constant expression}} expected-note {{read of dereferenced null pointer}}
- constexpr B &rb = (B&)*na; // expected-error {{constant expression}} expected-note {{read of dereferenced null pointer}}
+ constexpr A &ra = *nb; // expected-error {{constant expression}} expected-note {{dereferencing a null pointer}}
+ constexpr B &rb = (B&)*na; // expected-error {{constant expression}} expected-note {{dereferencing a null pointer}}
static_assert((A*)nb == 0, "");
static_assert((B*)na == 0, "");
constexpr const int &nf = nb->n; // expected-error {{constant expression}} expected-note {{cannot access field of null pointer}}
constexpr const int &mf = nb->m; // expected-error {{constant expression}} expected-note {{cannot access field of null pointer}}
constexpr const int *np1 = (int*)nullptr + 0; // ok
- constexpr const int *np2 = &(*(int(*)[4])nullptr)[0]; // expected-error {{constant expression}} expected-note {{read of dereferenced null pointer}}
- constexpr const int *np3 = &(*(int(*)[4])nullptr)[2]; // expected-error {{constant expression}} expected-note {{read of dereferenced null pointer is not allowed in a constant expression}}
+ constexpr const int *np2 = &(*(int(*)[4])nullptr)[0]; // expected-error {{constant expression}} expected-note {{dereferencing a null pointer}}
+ constexpr const int *np3 = &(*(int(*)[4])nullptr)[2]; // expected-error {{constant expression}} expected-note {{dereferencing a null pointer}}
struct C {
constexpr int f() const { return 0; }
@@ -485,7 +485,7 @@ namespace std {
namespace TypeId {
struct S { virtual void f(); };
constexpr S *p = 0;
- 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}}
+ 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}}
struct T {} t;
constexpr const std::type_info &ti2 = typeid(t);
diff --git a/clang/test/Sema/const-eval.c b/clang/test/Sema/const-eval.c
index f3df072710491..87c21120e7c5d 100644
--- a/clang/test/Sema/const-eval.c
+++ b/clang/test/Sema/const-eval.c
@@ -42,7 +42,7 @@ struct s {
EVAL_EXPR(19, ((int)&*(char*)10 == 10 ? 1 : -1));
// expected-error at -1 {{not an integer constant expression}} \
-// expected-note at -1 {{read of dereferenced null pointer is not allowed in a constant expression}}
+// expected-note at -1 {{dereferencing a null pointer is not allowed in a constant expression}}
EVAL_EXPR(20, __builtin_constant_p(*((int*) 10)));
diff --git a/clang/test/SemaCXX/constant-expression-cxx11.cpp b/clang/test/SemaCXX/constant-expression-cxx11.cpp
index b6a848267afe3..add8394d3b4b1 100644
--- a/clang/test/SemaCXX/constant-expression-cxx11.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx11.cpp
@@ -1413,8 +1413,8 @@ namespace ComplexConstexpr {
static_assert(t2p[2] == 0.0, ""); // expected-error {{constant expr}} expected-note {{one-past-the-end pointer}}
static_assert(t2p[3] == 0.0, ""); // expected-error {{constant expr}} expected-note {{cannot refer to element 3 of array of 2 elements}}
constexpr _Complex float *p = 0; // expected-warning {{'_Complex' is a C99 extension}}
- constexpr float pr = __real *p; // expected-error {{constant expr}} expected-note {{read of dereferenced null pointer}}
- constexpr float pi = __imag *p; // expected-error {{constant expr}} expected-note {{read of dereferenced null pointer}}
+ constexpr float pr = __real *p; // expected-error {{constant expr}} expected-note {{dereferencing a null pointer}}
+ constexpr float pi = __imag *p; // expected-error {{constant expr}} expected-note {{dereferencing a null pointer}}
constexpr const _Complex double *q = &test3 + 1; // expected-warning {{'_Complex' is a C99 extension}}
constexpr double qr = __real *q; // expected-error {{constant expr}} expected-note {{cannot access real component of pointer past the end}}
constexpr double qi = __imag *q; // expected-error {{constant expr}} expected-note {{cannot access imaginary component of pointer past the end}}
diff --git a/clang/test/SemaCXX/constant-expression-cxx14.cpp b/clang/test/SemaCXX/constant-expression-cxx14.cpp
index 3aa6384df42d0..4d45cca2d6f49 100644
--- a/clang/test/SemaCXX/constant-expression-cxx14.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx14.cpp
@@ -265,7 +265,7 @@ namespace const_modify {
namespace null {
constexpr int test(int *p) {
- return *p = 123; // expected-note {{read of dereferenced null pointer}}
+ return *p = 123; // expected-note {{dereferencing a null pointer}}
}
static_assert(test(0), ""); // expected-error {{constant expression}} expected-note {{in call}}
}
@@ -1325,7 +1325,7 @@ constexpr bool check = different_in_loop();
namespace GH48665 {
constexpr bool foo(int *i) {
int &j = *i;
- // expected-note at -1 {{read of dereferenced null pointer}}
+ // expected-note at -1 {{dereferencing a null pointer}}
return true;
}
@@ -1334,7 +1334,7 @@ static_assert(foo(nullptr), ""); // expected-note {{in call to 'foo(nullptr)'}}
constexpr bool foo_rvalue(int *i) {
int &&j = (int&&)*i;
- // expected-note at -1 {{read of dereferenced null pointer}}
+ // expected-note at -1 {{dereferencing a null pointer}}
return true;
}
static_assert(foo_rvalue(nullptr), ""); // expected-note {{in call to 'foo_rvalue(nullptr)'}}
@@ -1355,14 +1355,14 @@ struct Aggregate {
int &r;
};
constexpr bool test_agg(int *i) {
- Aggregate a{*i}; //expected-note {{read of dereferenced null pointer}}
+ Aggregate a{*i}; //expected-note {{dereferencing a null pointer}}
return true;
}
static_assert(test_agg(nullptr), ""); // expected-note {{in call to 'test_agg(nullptr)'}}
// expected-error at -1 {{static assertion expression is not an integral constant expression}}
struct B {
- constexpr B(int *p) : r{*p} {} // expected-note {{read of dereferenced null pointer}}
+ constexpr B(int *p) : r{*p} {} // expected-note {{dereferencing a null pointer}}
int &r;
};
diff --git a/clang/test/SemaCXX/constexpr-backtrace-limit.cpp b/clang/test/SemaCXX/constexpr-backtrace-limit.cpp
index 61991bf5d2931..f0c1206a4b8d3 100644
--- a/clang/test/SemaCXX/constexpr-backtrace-limit.cpp
+++ b/clang/test/SemaCXX/constexpr-backtrace-limit.cpp
@@ -15,14 +15,14 @@
// RUN: not %clang_cc1 -std=c++11 -fsyntax-only %s -fconstexpr-backtrace-limit=2 -fconstexpr-depth=8 -fno-caret-diagnostics 2>&1 | FileCheck %s -check-prefix=TEST3
// TEST3: constant expression
-// TEST3-NEXT: read of dereferenced null pointe
+// TEST3-NEXT: dereferencing a null pointer
// TEST3-NEXT: in call to 'recurse(0)'
// TEST3-NEXT: skipping 4 calls
// TEST3-NEXT: in call to 'recurse(5)'
// RUN: not %clang_cc1 -std=c++11 -fsyntax-only %s -fconstexpr-backtrace-limit=8 -fconstexpr-depth=8 -fno-caret-diagnostics 2>&1 | FileCheck %s -check-prefix=TEST4
// TEST4: constant expression
-// TEST4-NEXT: read of dereferenced null pointe
+// TEST4-NEXT: dereferencing a null pointer
// TEST4-NEXT: in call to 'recurse(0)'
// TEST4-NEXT: in call to 'recurse(1)'
// TEST4-NEXT: in call to 'recurse(2)'
>From fa1e9f48105561afeaa0edd05b520b7e4cc7b5a5 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinjabot at gmail.com>
Date: Thu, 10 Jul 2025 15:32:03 +0200
Subject: [PATCH 4/4] format
---
clang/include/clang/Basic/DiagnosticASTKinds.td | 5 +++--
clang/lib/AST/ExprConstant.cpp | 12 ++++++------
2 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td b/clang/include/clang/Basic/DiagnosticASTKinds.td
index 8d24bd1e86284..f0986a812fc19 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -223,8 +223,9 @@ def note_constexpr_ltor_incomplete_type : Note<
def note_constexpr_access_null : Note<
"%sub{access_kind}0 "
"dereferenced null pointer is not allowed in a constant expression">;
-def note_constexpr_dereferencing_null : Note<
- "dereferencing a null pointer is not allowed in a constant expression">;
+def note_constexpr_dereferencing_null
+ : Note<"dereferencing a null pointer is not allowed in a constant "
+ "expression">;
def note_constexpr_access_past_end : Note<
"%sub{access_kind}0 dereferenced one-past-the-end pointer "
"is not allowed in a constant expression">;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index e65ba59c19839..cf7a37ca4371e 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -1735,10 +1735,10 @@ namespace {
bool checkNullPointerForFoldAccess(EvalInfo &Info, const Expr *E,
AccessKinds AK) {
return checkNullPointerDiagnosingWith([&Info, E, AK] {
- if(AK == AccessKinds::AK_Dereference)
- Info.FFDiag(E, diag::note_constexpr_dereferencing_null);
+ if (AK == AccessKinds::AK_Dereference)
+ Info.FFDiag(E, diag::note_constexpr_dereferencing_null);
else
- Info.FFDiag(E, diag::note_constexpr_access_null) << AK;
+ Info.FFDiag(E, diag::note_constexpr_access_null) << AK;
});
}
@@ -4327,10 +4327,10 @@ static CompleteObject findCompleteObject(EvalInfo &Info, const Expr *E,
}
if (!LVal.Base) {
- if(AK == AccessKinds::AK_Dereference)
- Info.FFDiag(E, diag::note_constexpr_dereferencing_null);
+ if (AK == AccessKinds::AK_Dereference)
+ Info.FFDiag(E, diag::note_constexpr_dereferencing_null);
else
- Info.FFDiag(E, diag::note_constexpr_access_null) << AK;
+ Info.FFDiag(E, diag::note_constexpr_access_null) << AK;
return CompleteObject();
}
More information about the cfe-commits
mailing list