https://github.com/cor3ntin updated 
https://github.com/llvm/llvm-project/pull/143667

>From 83d2fe6d4fb870e816e6576636864f50586fe37a Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinja...@gmail.com>
Date: Mon, 9 Jun 2025 17:22:06 +0200
Subject: [PATCH 1/3] [Clang] Diagnose forming references to nullptr

Per [decl.ref],

> 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.

Note this does not fixes the new bytecode interpreter.

Fixes #48665
---
 .../include/clang/Basic/DiagnosticASTKinds.td |  9 ++++---
 clang/lib/AST/ByteCode/State.h                |  1 +
 clang/lib/AST/ExprConstant.cpp                | 26 ++++++++++++++-----
 .../SemaCXX/constant-expression-cxx14.cpp     | 23 +++++++++++++++-
 4 files changed, 48 insertions(+), 11 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td 
b/clang/include/clang/Basic/DiagnosticASTKinds.td
index d2cd86d05d55a..41ecda1cad960 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..649b58a4dd164 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_CheckReferenceInitialization
 };
 
 /// The order of this enum is important for diagnostics.
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index fa4e10e84de05..c02bf973c2552 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_CheckReferenceInitialization;
 }
 
 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_CheckReferenceInitialization:
     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_CheckReferenceInitialization;
 }
 
 /// 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_CheckReferenceInitialization:
   case AK_ReadObjectRepresentation:
   case AK_Assign:
   case AK_Construct:
@@ -4426,7 +4428,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, 
const Expr *E,
 
     // Unless we're looking at a local variable or argument in a constexpr 
call,
     // the variable we're reading must be const.
-    if (!Frame) {
+    if (!Frame && AK != clang::AK_CheckReferenceInitialization) {
       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
@@ -4503,7 +4505,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, 
const Expr *E,
   } else {
     const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
 
-    if (!Frame) {
+    if (!Frame && AK != clang::AK_CheckReferenceInitialization) {
       if (const MaterializeTemporaryExpr *MTE =
               dyn_cast_or_null<MaterializeTemporaryExpr>(Base)) {
         assert(MTE->getStorageDuration() == SD_Static &&
@@ -4557,7 +4559,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, 
const Expr *E,
         NoteLValueLocation(Info, LVal.Base);
         return CompleteObject();
       }
-    } else {
+    } else if (AK != clang::AK_CheckReferenceInitialization) {
       BaseVal = Frame->getTemporary(Base, LVal.Base.getVersion());
       assert(BaseVal && "missing value for temporary");
     }
@@ -5243,7 +5245,19 @@ static bool EvaluateVarDecl(EvalInfo &Info, const 
VarDecl *VD) {
   if (InitE->isValueDependent())
     return false;
 
-  if (!EvaluateInPlace(Val, Info, Result, InitE)) {
+  if (VD->getType()->isReferenceType() && InitE->isGLValue()) {
+    if (!EvaluateLValue(InitE, Result, Info))
+      return false;
+    CompleteObject Obj = findCompleteObject(
+        Info, InitE, AK_CheckReferenceInitialization, Result, 
InitE->getType());
+    if (Result.Designator.isOnePastTheEnd()) {
+      Info.FFDiag(InitE, diag::note_constexpr_access_past_end)
+          << AK_CheckReferenceInitialization;
+      return false;
+    }
+    Result.moveInto(Val);
+    return !!Obj;
+  } else if (!EvaluateInPlace(Val, Info, Result, InitE)) {
     // Wipe out any partially-computed value, to allow tracking that this
     // evaluation failed.
     Val = APValue();
diff --git a/clang/test/SemaCXX/constant-expression-cxx14.cpp 
b/clang/test/SemaCXX/constant-expression-cxx14.cpp
index e16a69df3830d..d8ebe92131ddc 100644
--- a/clang/test/SemaCXX/constant-expression-cxx14.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx14.cpp
@@ -250,7 +250,7 @@ namespace subobject {
 namespace lifetime {
   constexpr int &&id(int &&n) { return static_cast<int&&>(n); }
   constexpr int &&dead() { return id(0); } // expected-note {{temporary 
created here}}
-  constexpr int bad() { int &&n = dead(); n = 1; return n; } // expected-note 
{{assignment to temporary whose lifetime has ended}}
+  constexpr int bad() { int &&n = dead(); n = 1; return n; } // expected-note 
{{read of temporary whose lifetime has ended}}
   static_assert(bad(), ""); // expected-error {{constant expression}} 
expected-note {{in call}}
 }
 
@@ -1321,3 +1321,24 @@ constexpr bool check = different_in_loop();
   // expected-error@-1 {{}} expected-note@-1 {{in call}}
 
 }
+
+namespace GH48665 {
+constexpr bool foo(int *i) {
+    int &j = *i;
+    // expected-note@-1 {{read of dereferenced null pointer is not allowed in 
a constant expression}}
+    return true;
+}
+
+static_assert(foo(nullptr), ""); // expected-note {{in call to 'foo(nullptr)'}}
+// expected-error@-1 {{static assertion expression is not an integral constant 
expression}}
+
+int arr[3]; // expected-note 2{{declared here}}
+constexpr bool f() { // cxx14_20-error {{constexpr function never produces a 
constant expression}}
+  int &r  = arr[3]; // cxx14_20-note {{read of dereferenced one-past-the-end 
pointer is not allowed in a constant expression}} \
+                    // expected-warning {{array index 3 is past the end of the 
array}}\
+                    // expected-note {{initializer of 'arr' is unknown}}
+  return true;
+}
+static_assert(f(), ""); // expected-note {{in call to 'f()'}}
+// expected-error@-1 {{static assertion expression is not an integral constant 
expression}}
+}

>From e467b500ff11f07c3be7cb8ad77e62ecf8776dc4 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinja...@gmail.com>
Date: Thu, 12 Jun 2025 14:25:19 +0200
Subject: [PATCH 2/3] Apply feedback, check constructors and aggregates

---
 .../include/clang/Basic/DiagnosticASTKinds.td |  2 +-
 clang/lib/AST/ByteCode/State.h                |  2 +-
 clang/lib/AST/ExprConstant.cpp                | 83 +++++++++++++------
 .../SemaCXX/constant-expression-cxx14.cpp     | 37 +++++++--
 4 files changed, 90 insertions(+), 34 deletions(-)

diff --git a/clang/include/clang/Basic/DiagnosticASTKinds.td 
b/clang/include/clang/Basic/DiagnosticASTKinds.td
index 41ecda1cad960..5ec61dda5d7e0 100644
--- a/clang/include/clang/Basic/DiagnosticASTKinds.td
+++ b/clang/include/clang/Basic/DiagnosticASTKinds.td
@@ -178,7 +178,7 @@ 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">;
+          "destruction of|read of|binding a reference to}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 649b58a4dd164..8fc5b0c7e534c 100644
--- a/clang/lib/AST/ByteCode/State.h
+++ b/clang/lib/AST/ByteCode/State.h
@@ -35,7 +35,7 @@ enum AccessKinds {
   AK_Construct,
   AK_Destroy,
   AK_IsWithinLifetime,
-  AK_CheckReferenceInitialization
+  AK_ReferenceInitialization
 };
 
 /// The order of this enum is important for diagnostics.
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index c02bf973c2552..edaac771cee14 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_CheckReferenceInitialization;
+         AK == AK_IsWithinLifetime || AK == AK_ReferenceInitialization;
 }
 
 static bool isModification(AccessKinds AK) {
@@ -1540,7 +1540,7 @@ static bool isModification(AccessKinds AK) {
   case AK_DynamicCast:
   case AK_TypeId:
   case AK_IsWithinLifetime:
-  case AK_CheckReferenceInitialization:
+  case AK_ReferenceInitialization:
     return false;
   case AK_Assign:
   case AK_Increment:
@@ -1559,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_CheckReferenceInitialization;
+         AK != AK_IsWithinLifetime && AK != AK_ReferenceInitialization;
 }
 
 /// Is this kind of axcess valid on an indeterminate object value?
@@ -1572,7 +1572,7 @@ static bool isValidIndeterminateAccess(AccessKinds AK) {
     return false;
 
   case AK_IsWithinLifetime:
-  case AK_CheckReferenceInitialization:
+  case AK_ReferenceInitialization:
   case AK_ReadObjectRepresentation:
   case AK_Assign:
   case AK_Construct:
@@ -4420,6 +4420,9 @@ static CompleteObject findCompleteObject(EvalInfo &Info, 
const Expr *E,
       return CompleteObject();
     }
 
+    // if(AK == clang::AK_ReferenceInitialization)
+    //     return CompleteObject(LVal.getLValueBase(), nullptr, BaseType);
+
     bool IsConstant = BaseType.isConstant(Info.Ctx);
     bool ConstexprVar = false;
     if (const auto *VD = dyn_cast_if_present<VarDecl>(
@@ -4428,7 +4431,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, 
const Expr *E,
 
     // Unless we're looking at a local variable or argument in a constexpr 
call,
     // the variable we're reading must be const.
-    if (!Frame && AK != clang::AK_CheckReferenceInitialization) {
+    if (AK != clang::AK_ReferenceInitialization && !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
@@ -4492,7 +4495,9 @@ static CompleteObject findCompleteObject(EvalInfo &Info, 
const Expr *E,
       }
     }
 
-    if (!evaluateVarDeclInit(Info, E, VD, Frame, LVal.getLValueVersion(), 
BaseVal))
+    if (AK != clang::AK_ReferenceInitialization &&
+        !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);
@@ -4505,7 +4510,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, 
const Expr *E,
   } else {
     const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
 
-    if (!Frame && AK != clang::AK_CheckReferenceInitialization) {
+    if (AK != clang::AK_ReferenceInitialization && !Frame) {
       if (const MaterializeTemporaryExpr *MTE =
               dyn_cast_or_null<MaterializeTemporaryExpr>(Base)) {
         assert(MTE->getStorageDuration() == SD_Static &&
@@ -4559,7 +4564,7 @@ static CompleteObject findCompleteObject(EvalInfo &Info, 
const Expr *E,
         NoteLValueLocation(Info, LVal.Base);
         return CompleteObject();
       }
-    } else if (AK != clang::AK_CheckReferenceInitialization) {
+    } else if (AK != clang::AK_ReferenceInitialization) {
       BaseVal = Frame->getTemporary(Base, LVal.Base.getVersion());
       assert(BaseVal && "missing value for temporary");
     }
@@ -5225,6 +5230,24 @@ enum EvalStmtResult {
 };
 }
 
+static bool EvaluateInitForDeclOfReferenceType(EvalInfo &Info,
+                                               const ValueDecl *D,
+                                               const Expr *Init, LValue 
&Result,
+                                               APValue &Val) {
+  assert(Init->isGLValue() && D->getType()->isReferenceType());
+  if (!EvaluateLValue(Init, Result, Info))
+    return false;
+  CompleteObject Obj = findCompleteObject(
+      Info, Init, AK_ReferenceInitialization, Result, Init->getType());
+  if (!Result.Designator.Invalid && Result.Designator.isOnePastTheEnd()) {
+    Info.FFDiag(Init, diag::note_constexpr_access_past_end)
+        << AK_ReferenceInitialization;
+    return false;
+  }
+  Result.moveInto(Val);
+  return !!Obj;
+}
+
 static bool EvaluateVarDecl(EvalInfo &Info, const VarDecl *VD) {
   if (VD->isInvalidDecl())
     return false;
@@ -5245,18 +5268,8 @@ static bool EvaluateVarDecl(EvalInfo &Info, const 
VarDecl *VD) {
   if (InitE->isValueDependent())
     return false;
 
-  if (VD->getType()->isReferenceType() && InitE->isGLValue()) {
-    if (!EvaluateLValue(InitE, Result, Info))
-      return false;
-    CompleteObject Obj = findCompleteObject(
-        Info, InitE, AK_CheckReferenceInitialization, Result, 
InitE->getType());
-    if (Result.Designator.isOnePastTheEnd()) {
-      Info.FFDiag(InitE, diag::note_constexpr_access_past_end)
-          << AK_CheckReferenceInitialization;
-      return false;
-    }
-    Result.moveInto(Val);
-    return !!Obj;
+  if (VD->getType()->isReferenceType()) {
+    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.
@@ -6897,9 +6910,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()) {
+        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())
@@ -10926,9 +10948,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()) {
+      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/SemaCXX/constant-expression-cxx14.cpp 
b/clang/test/SemaCXX/constant-expression-cxx14.cpp
index d8ebe92131ddc..57a172ada8adc 100644
--- a/clang/test/SemaCXX/constant-expression-cxx14.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx14.cpp
@@ -250,7 +250,7 @@ namespace subobject {
 namespace lifetime {
   constexpr int &&id(int &&n) { return static_cast<int&&>(n); }
   constexpr int &&dead() { return id(0); } // expected-note {{temporary 
created here}}
-  constexpr int bad() { int &&n = dead(); n = 1; return n; } // expected-note 
{{read of temporary whose lifetime has ended}}
+  constexpr int bad() { int &&n = dead(); n = 1; return n; } // expected-note 
{{binding a reference to temporary whose lifetime has ended}}
   static_assert(bad(), ""); // expected-error {{constant expression}} 
expected-note {{in call}}
 }
 
@@ -1325,20 +1325,45 @@ constexpr bool check = different_in_loop();
 namespace GH48665 {
 constexpr bool foo(int *i) {
     int &j = *i;
-    // expected-note@-1 {{read of dereferenced null pointer is not allowed in 
a constant expression}}
+    // expected-note@-1 {{binding a reference to dereferenced null pointer is 
not allowed in a constant expression}}
     return true;
 }
 
 static_assert(foo(nullptr), ""); // expected-note {{in call to 'foo(nullptr)'}}
 // expected-error@-1 {{static assertion expression is not an integral constant 
expression}}
 
-int arr[3]; // expected-note 2{{declared here}}
+int arr[3]; // expected-note {{declared here}}
 constexpr bool f() { // cxx14_20-error {{constexpr function never produces a 
constant expression}}
-  int &r  = arr[3]; // cxx14_20-note {{read of dereferenced one-past-the-end 
pointer is not allowed in a constant expression}} \
-                    // expected-warning {{array index 3 is past the end of the 
array}}\
-                    // expected-note {{initializer of 'arr' is unknown}}
+  int &r  = arr[3]; // cxx14_20-note {{binding a reference to dereferenced 
one-past-the-end pointer is not allowed in a constant expression}} \
+                    // expected-note {{binding a reference to dereferenced 
one-past-the-end pointer is not allowed in a constant expression}} \
+                    // 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@-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 {{binding a reference to dereferenced null 
pointer is not allowed in a constant expression}}
+   return true;
+}
+static_assert(test_agg(nullptr), ""); // expected-note {{in call to 
'test_agg(nullptr)'}}
+// expected-error@-1 {{static assertion expression is not an integral constant 
expression}}
+
+struct B {
+  constexpr B(int *p) : r{*p} {}  // expected-note {{binding a reference to 
dereferenced null pointer is not allowed in a constant expression}}
+  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@-1 {{static assertion expression is not an integral constant 
expression}}
+
 }

>From fff79c4caca6a4d253dadba916055c3afcd07a31 Mon Sep 17 00:00:00 2001
From: Corentin Jabot <corentinja...@gmail.com>
Date: Fri, 13 Jun 2025 17:31:45 +0200
Subject: [PATCH 3/3] cleanup, add comments

---
 clang/lib/AST/ExprConstant.cpp | 27 ++++++++++++++++++++-------
 1 file changed, 20 insertions(+), 7 deletions(-)

diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index edaac771cee14..6fb74a5d5ec6d 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -4420,9 +4420,6 @@ static CompleteObject findCompleteObject(EvalInfo &Info, 
const Expr *E,
       return CompleteObject();
     }
 
-    // if(AK == clang::AK_ReferenceInitialization)
-    //     return CompleteObject(LVal.getLValueBase(), nullptr, BaseType);
-
     bool IsConstant = BaseType.isConstant(Info.Ctx);
     bool ConstexprVar = false;
     if (const auto *VD = dyn_cast_if_present<VarDecl>(
@@ -4430,7 +4427,8 @@ 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.
+    // the variable we're reading must be const (unless we are binding to a
+    // reference).
     if (AK != clang::AK_ReferenceInitialization && !Frame) {
       if (IsAccess && isa<ParmVarDecl>(VD)) {
         // Access of a parameter that's not associated with a frame isn't going
@@ -4495,6 +4493,8 @@ static CompleteObject findCompleteObject(EvalInfo &Info, 
const Expr *E,
       }
     }
 
+    // When binding to a reference, the variable does not need to be constexpr
+    // or have constant initalization.
     if (AK != clang::AK_ReferenceInitialization &&
         !evaluateVarDeclInit(Info, E, VD, Frame, LVal.getLValueVersion(),
                              BaseVal))
@@ -4507,10 +4507,13 @@ 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_ReferenceInitialization) {
     const Expr *Base = LVal.Base.dyn_cast<const Expr*>();
 
-    if (AK != clang::AK_ReferenceInitialization && !Frame) {
+    if (!Frame) {
       if (const MaterializeTemporaryExpr *MTE =
               dyn_cast_or_null<MaterializeTemporaryExpr>(Base)) {
         assert(MTE->getStorageDuration() == SD_Static &&
@@ -5230,22 +5233,32 @@ enum EvalStmtResult {
 };
 }
 
+/// 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;
   CompleteObject Obj = findCompleteObject(
       Info, Init, AK_ReferenceInitialization, Result, Init->getType());
+  if (!Obj)
+    return false;
   if (!Result.Designator.Invalid && Result.Designator.isOnePastTheEnd()) {
     Info.FFDiag(Init, diag::note_constexpr_access_past_end)
         << AK_ReferenceInitialization;
     return false;
   }
+  // save the result
   Result.moveInto(Val);
-  return !!Obj;
+  return true;
 }
 
 static bool EvaluateVarDecl(EvalInfo &Info, const VarDecl *VD) {

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to