Author: Timm Baeder
Date: 2026-05-05T02:47:36+02:00
New Revision: 2b430502a2114b77e6495d90ac52359f73beb550

URL: 
https://github.com/llvm/llvm-project/commit/2b430502a2114b77e6495d90ac52359f73beb550
DIFF: 
https://github.com/llvm/llvm-project/commit/2b430502a2114b77e6495d90ac52359f73beb550.diff

LOG: [clang][ExprConst] Add another missing `NoteLValueLocation()` call 
(#195098)

This is a little more work since it requires a new parameter for all the
`found()` handlers.

Added: 
    

Modified: 
    clang/lib/AST/ExprConstant.cpp
    clang/test/SemaCXX/constant-expression-cxx14.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 1a4c962801077..3f3a80f5b77a3 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -4245,7 +4245,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const 
CompleteObject &Obj,
     }
 
     if (I == N) {
-      if (!handler.found(*O, ObjType))
+      if (!handler.found(*O, ObjType, Obj.Base))
         return false;
 
       // If we modified a bit-field, truncate it to the right width.
@@ -4342,7 +4342,7 @@ findSubobject(EvalInfo &Info, const Expr *E, const 
CompleteObject &Obj,
         expandVector(*O, NumElements);
       }
       assert(O->isVector() && "unexpected object during vector element 
access");
-      return handler.found(O->getVectorElt(Index), ObjType);
+      return handler.found(O->getVectorElt(Index), ObjType, Obj.Base);
     } else if (const FieldDecl *Field = getAsField(Sub.Entries[I])) {
       if (Field->isMutable() &&
           !Obj.mayAccessMutableMembers(Info, handler.AccessKind)) {
@@ -4402,7 +4402,7 @@ struct ExtractSubobjectHandler {
 
   typedef bool result_type;
   bool failed() { return false; }
-  bool found(APValue &Subobj, QualType SubobjType) {
+  bool found(APValue &Subobj, QualType SubobjType, APValue::LValueBase Base) {
     Result = Subobj;
     if (AccessKind == AK_ReadObjectRepresentation)
       return true;
@@ -4448,7 +4448,7 @@ struct ModifySubobjectHandler {
   }
 
   bool failed() { return false; }
-  bool found(APValue &Subobj, QualType SubobjType) {
+  bool found(APValue &Subobj, QualType SubobjType, APValue::LValueBase Base) {
     if (!checkConst(SubobjType))
       return false;
     // We've been given ownership of NewVal, so just swap it in.
@@ -4978,7 +4978,7 @@ struct CompoundAssignSubobjectHandler {
   }
 
   bool failed() { return false; }
-  bool found(APValue &Subobj, QualType SubobjType) {
+  bool found(APValue &Subobj, QualType SubobjType, APValue::LValueBase Base) {
     switch (Subobj.getKind()) {
     case APValue::Int:
       return found(Subobj.getInt(), SubobjType);
@@ -4997,6 +4997,7 @@ struct CompoundAssignSubobjectHandler {
       Info.FFDiag(E, diag::note_constexpr_access_uninit)
           << /*read of=*/0 << /*uninitialized object=*/1
           << E->getLHS()->getSourceRange();
+      NoteLValueLocation(Info, Base);
       return false;
     default:
       // FIXME: can this happen?
@@ -5125,7 +5126,7 @@ struct IncDecSubobjectHandler {
   }
 
   bool failed() { return false; }
-  bool found(APValue &Subobj, QualType SubobjType) {
+  bool found(APValue &Subobj, QualType SubobjType, APValue::LValueBase Base) {
     // Stash the old value. Also clear Old, so we don't clobber it later
     // if we're post-incrementing a complex.
     if (Old) {
@@ -6412,7 +6413,9 @@ struct CheckDynamicTypeHandler {
   AccessKinds AccessKind;
   typedef bool result_type;
   bool failed() { return false; }
-  bool found(APValue &Subobj, QualType SubobjType) { return true; }
+  bool found(APValue &Subobj, QualType SubobjType, APValue::LValueBase Base) {
+    return true;
+  }
   bool found(APSInt &Value, QualType SubobjType) { return true; }
   bool found(APFloat &Value, QualType SubobjType) { return true; }
 };
@@ -6762,7 +6765,7 @@ struct StartLifetimeOfUnionMemberHandler {
 
   typedef bool result_type;
   bool failed() { return Failed; }
-  bool found(APValue &Subobj, QualType SubobjType) {
+  bool found(APValue &Subobj, QualType SubobjType, APValue::LValueBase Base) {
     // We are supposed to perform no initialization but begin the lifetime of
     // the object. We interpret that as meaning to do what default
     // initialization of the object would do if all constructors involved were
@@ -7480,7 +7483,7 @@ struct DestroyObjectHandler {
 
   typedef bool result_type;
   bool failed() { return false; }
-  bool found(APValue &Subobj, QualType SubobjType) {
+  bool found(APValue &Subobj, QualType SubobjType, APValue::LValueBase Base) {
     return HandleDestructionImpl(Info, E->getSourceRange(), This, Subobj,
                                  SubobjType);
   }
@@ -10865,7 +10868,8 @@ bool PointerExprEvaluator::VisitCXXNewExpr(const 
CXXNewExpr *E) {
         }
         return true;
       }
-      bool found(APValue &Subobj, QualType SubobjType) {
+      bool found(APValue &Subobj, QualType SubobjType,
+                 APValue::LValueBase Base) {
         if (!checkConst(SubobjType))
           return false;
         // FIXME: Reject the cases where [basic.life]p8 would not permit the
@@ -22525,6 +22529,11 @@ struct IsWithinLifetimeHandler {
   using result_type = std::optional<bool>;
   std::optional<bool> failed() { return std::nullopt; }
   template <typename T>
+  std::optional<bool> found(T &Subobj, QualType SubobjType,
+                            APValue::LValueBase) {
+    return true;
+  }
+  template <typename T>
   std::optional<bool> found(T &Subobj, QualType SubobjType) {
     return true;
   }

diff  --git a/clang/test/SemaCXX/constant-expression-cxx14.cpp 
b/clang/test/SemaCXX/constant-expression-cxx14.cpp
index 9c0e87cac54cf..fb7fd5b528b05 100644
--- a/clang/test/SemaCXX/constant-expression-cxx14.cpp
+++ b/clang/test/SemaCXX/constant-expression-cxx14.cpp
@@ -1284,16 +1284,20 @@ namespace TemporaryWithBadPointer {
 
 namespace UninitCompoundAssign {
 constexpr int scalar(int a) {
-  int sum; // cxx14-warning {{uninitialized variable in a constexpr function 
is a C++20 extension}}
-  sum += a; // expected-note {{read of uninitialized object}};
+  int sum; // cxx14-warning {{uninitialized variable in a constexpr function 
is a C++20 extension}} \
+           // #sum-decl
+  sum += a; // expected-note {{read of uninitialized object}} \
+            // expected-note@#sum-decl {{declared here}}
   return 0;
 }
 static_assert(scalar(3), ""); // expected-error {{constant expression}} \
                               // expected-note {{in call to 'scalar(3)'}}
 
 constexpr int array(int a) {
-  int arr[3]; // cxx14-warning {{uninitialized variable in a constexpr 
function is a C++20 extension}}
-  arr[1] += a; // expected-note {{read of uninitialized object}};
+  int arr[3]; // cxx14-warning {{uninitialized variable in a constexpr 
function is a C++20 extension}} \
+              // #arr-decl
+  arr[1] += a; // expected-note {{read of uninitialized object}} \
+               // expected-note@#arr-decl {{declared here}}
   return 0;
 }
 static_assert(array(3), ""); // expected-error {{constant expression}} \
@@ -1304,8 +1308,9 @@ struct Foo {
   constexpr Foo() {} // cxx14-warning {{constexpr constructor that does not 
initialize all members is a C++20 extension}}
 };
 constexpr int field(int a) {
-  Foo f;
-  f.val += a; // expected-note {{read of uninitialized object}};
+  Foo f; // #f-decl
+  f.val += a; // expected-note {{read of uninitialized object}} \
+              // expected-note@#f-decl {{declared here}}
   return 0;
 }
 static_assert(field(3), ""); // expected-error {{constant expression}} \


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to