llvmbot wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Timm Baeder (tbaederr)

<details>
<summary>Changes</summary>

E.g. for

```c++
constexpr int unInitLocal() {
  int a;
  return a; // both-note {{read of uninitialized object}}
}
static_assert(unInitLocal() == 0, ""); // both-error {{not an integral constant 
expression}} \
                                       // both-note {{in call to 
'unInitLocal()'}}
```

we now diagnose:
```console
array.cpp:896:15: error: static assertion expression is not an integral 
constant expression
  896 | static_assert(unInitLocal() == 0, ""); // both-error {{not an integral 
constant expression}} \
      |               ^~~~~~~~~~~~~~~~~~
array.cpp:894:10: note: read of uninitialized object is not allowed in a 
constant expression
  894 |   return a; // both-note {{read of uninitialized object}}
      |          ^
array.cpp:896:15: note: in call to 'unInitLocal()'
  896 | static_assert(unInitLocal() == 0, ""); // both-error {{not an integral 
constant expression}} \
      |               ^~~~~~~~~~~~~
array.cpp:893:7: note: declared here
  893 |   int a;
      |       ^
1 warning and 1 error generated.
```
and point at the object that we were trying to read from. This adds an 
`NoteLValueLocation()` call to the emission of `note_constexpr_access_uninit`, 
which is already done in other places:

https://github.com/llvm/llvm-project/blob/7ae5fe63dd979eae13ea04e166f94056ec1306ca/clang/lib/AST/ExprConstant.cpp#L4565-L4570

---

Patch is 56.01 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/192206.diff


33 Files Affected:

- (modified) clang/lib/AST/ByteCode/Interp.cpp (+34-26) 
- (modified) clang/lib/AST/ByteCode/Interp.h (+2-3) 
- (modified) clang/lib/AST/ExprConstant.cpp (+3-1) 
- (modified) clang/test/AST/ByteCode/builtin-bit-cast-bitfields.cpp (+6-4) 
- (modified) clang/test/AST/ByteCode/builtin-bit-cast-long-double.cpp (+1-1) 
- (modified) clang/test/AST/ByteCode/builtin-functions.cpp (+1-1) 
- (modified) clang/test/AST/ByteCode/constexpr-nqueens.cpp (+3-1) 
- (modified) clang/test/AST/ByteCode/cxx11.cpp (+2-1) 
- (modified) clang/test/AST/ByteCode/cxx17.cpp (+2-1) 
- (modified) clang/test/AST/ByteCode/cxx20.cpp (+12-9) 
- (modified) clang/test/AST/ByteCode/cxx2a.cpp (+2-1) 
- (modified) clang/test/AST/ByteCode/lifetimes.cpp (+3-3) 
- (modified) clang/test/AST/ByteCode/lifetimes26.cpp (+4-4) 
- (modified) clang/test/AST/ByteCode/literals.cpp (+1-1) 
- (modified) clang/test/AST/ByteCode/new-delete.cpp (+6-5) 
- (modified) clang/test/AST/ByteCode/placement-new.cpp (+5-4) 
- (modified) clang/test/AST/ByteCode/records.cpp (+1-1) 
- (modified) clang/test/AST/ByteCode/unions.cpp (+2-2) 
- (modified) clang/test/C/C23/n3006.c (+3-2) 
- (modified) clang/test/CXX/drs/cwg2026.cpp (+6) 
- (modified) clang/test/CXX/drs/cwg3xx.cpp (+1) 
- (modified) clang/test/CXX/expr/expr.const/p2-0x.cpp (+1-1) 
- (modified) clang/test/Sema/constexpr.c (+3-2) 
- (modified) clang/test/SemaCXX/builtin-is-within-lifetime.cpp (+3-3) 
- (modified) clang/test/SemaCXX/constant-expression-cxx11.cpp (+21-10) 
- (modified) clang/test/SemaCXX/constant-expression-cxx14.cpp (+14-9) 
- (modified) clang/test/SemaCXX/constant-expression-cxx2a.cpp (+18-11) 
- (modified) clang/test/SemaCXX/constexpr-builtin-bit-cast.cpp (+3-3) 
- (modified) clang/test/SemaCXX/constexpr-printing.cpp (+3-1) 
- (modified) clang/test/SemaCXX/constexpr-value-init.cpp (+15-5) 
- (modified) clang/test/SemaCXX/cxx2a-constexpr-dynalloc.cpp (+4-2) 
- (modified) clang/test/SemaCXX/cxx2c-constexpr-placement-new.cpp (+2-2) 
- (modified) clang/test/SemaCXX/static-assert-cxx26.cpp (+1-1) 


``````````diff
diff --git a/clang/lib/AST/ByteCode/Interp.cpp 
b/clang/lib/AST/ByteCode/Interp.cpp
index abcf55bfa670d..5bc1067518558 100644
--- a/clang/lib/AST/ByteCode/Interp.cpp
+++ b/clang/lib/AST/ByteCode/Interp.cpp
@@ -83,6 +83,17 @@ static void diagnoseMissingInitializer(InterpState &S, 
CodePtr OpPC,
   S.Note(VD->getLocation(), diag::note_declared_at) << VD->getSourceRange();
 }
 
+static void noteValueLocation(InterpState &S, const Block *B) {
+  const Descriptor *Desc = B->getDescriptor();
+
+  if (B->isDynamic())
+    S.Note(Desc->getLocation(), diag::note_constexpr_dynamic_alloc_here);
+  else if (B->isTemporary())
+    S.Note(Desc->getLocation(), diag::note_constexpr_temporary_here);
+  else
+    S.Note(Desc->getLocation(), diag::note_declared_at);
+}
+
 static void diagnoseNonConstVariable(InterpState &S, CodePtr OpPC,
                                      const ValueDecl *VD);
 static bool diagnoseUnknownDecl(InterpState &S, CodePtr OpPC,
@@ -185,8 +196,7 @@ static bool CheckTemporary(InterpState &S, CodePtr OpPC, 
const Block *B,
         !MTE->isUsableInConstantExpressions(S.getASTContext())) {
       const SourceInfo &E = S.Current->getSource(OpPC);
       S.FFDiag(E, diag::note_constexpr_access_static_temporary, 1) << AK;
-      S.Note(B->getDescriptor()->getLocation(),
-             diag::note_constexpr_temporary_here);
+      noteValueLocation(S, B);
       return false;
     }
   }
@@ -418,14 +428,9 @@ bool CheckLive(InterpState &S, CodePtr OpPC, const Pointer 
&Ptr,
     if (Ptr.isDynamic()) {
       S.FFDiag(Src, diag::note_constexpr_access_deleted_object) << AK;
     } else if (!S.checkingPotentialConstantExpression()) {
-      bool IsTemp = Ptr.isTemporary();
       S.FFDiag(Src, diag::note_constexpr_access_uninit)
           << AK << /*uninitialized=*/false << S.Current->getRange(OpPC);
-
-      if (IsTemp)
-        S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
-      else
-        S.Note(Ptr.getDeclLoc(), diag::note_declared_at);
+      noteValueLocation(S, Ptr.block());
     }
 
     return false;
@@ -648,14 +653,16 @@ bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, 
const Pointer &Ptr,
                            AccessKinds AK) {
   assert(Ptr.isLive());
   assert(!Ptr.isInitialized());
-  return DiagnoseUninitialized(S, OpPC, Ptr.isExtern(), Ptr.getDeclDesc(), AK);
+  return DiagnoseUninitialized(S, OpPC, Ptr.isExtern(), Ptr.block(), AK);
 }
 
 bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, bool Extern,
-                           const Descriptor *Desc, AccessKinds AK) {
+                           const Block *B, AccessKinds AK) {
   if (Extern && S.checkingPotentialConstantExpression())
     return false;
 
+  const Descriptor *Desc = B->getDescriptor();
+
   if (const auto *VD = Desc->asVarDecl();
       VD && (VD->isConstexpr() || VD->hasGlobalStorage())) {
 
@@ -670,6 +677,7 @@ bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, 
bool Extern,
         // Diagnose as "read of object outside its lifetime".
         S.FFDiag(Loc, diag::note_constexpr_access_uninit)
             << AK << /*IsIndeterminate=*/false;
+        S.Note(VD->getLocation(), diag::note_declared_at);
       }
       return false;
     }
@@ -687,21 +695,27 @@ bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, 
bool Extern,
   if (!S.checkingPotentialConstantExpression()) {
     S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit)
         << AK << /*uninitialized=*/true << S.Current->getRange(OpPC);
+    noteValueLocation(S, B);
   }
   return false;
 }
 
 static bool CheckLifetime(InterpState &S, CodePtr OpPC, Lifetime LT,
-                          AccessKinds AK) {
+                          const Block *B, AccessKinds AK) {
   if (LT == Lifetime::Started)
     return true;
 
   if (!S.checkingPotentialConstantExpression()) {
     S.FFDiag(S.Current->getSource(OpPC), diag::note_constexpr_access_uninit)
         << AK << /*uninitialized=*/false << S.Current->getRange(OpPC);
+    noteValueLocation(S, B);
   }
   return false;
 }
+static bool CheckLifetime(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
+                          AccessKinds AK) {
+  return CheckLifetime(S, OpPC, Ptr.getLifetime(), Ptr.block(), AK);
+}
 
 static bool CheckWeak(InterpState &S, CodePtr OpPC, const Block *B) {
   if (!B->isWeak())
@@ -733,8 +747,7 @@ bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const 
Block *B) {
   if (!CheckConstant(S, OpPC, B->getDescriptor()))
     return false;
   if (Desc.InitState != GlobalInitState::Initialized)
-    return DiagnoseUninitialized(S, OpPC, B->isExtern(), B->getDescriptor(),
-                                 AK_Read);
+    return DiagnoseUninitialized(S, OpPC, B->isExtern(), B, AK_Read);
   if (!CheckTemporary(S, OpPC, B, AK_Read))
     return false;
   if (B->getDescriptor()->IsVolatile) {
@@ -755,11 +768,10 @@ bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const 
Block *B) {
 bool CheckLocalLoad(InterpState &S, CodePtr OpPC, const Block *B) {
   assert(!B->isExtern());
   const auto &Desc = *reinterpret_cast<const InlineDescriptor *>(B->rawData());
-  if (!CheckLifetime(S, OpPC, Desc.LifeState, AK_Read))
+  if (!CheckLifetime(S, OpPC, Desc.LifeState, B, AK_Read))
     return false;
   if (!Desc.IsInitialized)
-    return DiagnoseUninitialized(S, OpPC, /*Extern=*/false, B->getDescriptor(),
-                                 AK_Read);
+    return DiagnoseUninitialized(S, OpPC, /*Extern=*/false, B, AK_Read);
   if (B->getDescriptor()->IsVolatile) {
     if (!S.getLangOpts().CPlusPlus)
       return Invalid(S, OpPC);
@@ -805,7 +817,7 @@ bool CheckLoad(InterpState &S, CodePtr OpPC, const Pointer 
&Ptr,
     return false;
   if (!CheckActive(S, OpPC, Ptr, AK))
     return false;
-  if (!CheckLifetime(S, OpPC, Ptr.getLifetime(), AK))
+  if (!CheckLifetime(S, OpPC, Ptr, AK))
     return false;
   if (!Ptr.isInitialized())
     return DiagnoseUninitialized(S, OpPC, Ptr, AK);
@@ -843,7 +855,7 @@ bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const 
Pointer &Ptr) {
 
   if (!CheckActive(S, OpPC, Ptr, AK_Read))
     return false;
-  if (!CheckLifetime(S, OpPC, Ptr.getLifetime(), AK_Read))
+  if (!CheckLifetime(S, OpPC, Ptr, AK_Read))
     return false;
   if (!Ptr.isInitialized())
     return DiagnoseUninitialized(S, OpPC, Ptr, AK_Read);
@@ -868,7 +880,7 @@ bool CheckStore(InterpState &S, CodePtr OpPC, const Pointer 
&Ptr,
       return false;
     return CheckDummy(S, OpPC, Ptr.block(), AK_Assign);
   }
-  if (!CheckLifetime(S, OpPC, Ptr.getLifetime(), AK_Assign))
+  if (!CheckLifetime(S, OpPC, Ptr, AK_Assign))
     return false;
   if (!CheckRange(S, OpPC, Ptr, AK_Assign))
     return false;
@@ -1138,11 +1150,7 @@ bool CheckDeleteSource(InterpState &S, CodePtr OpPC, 
const Expr *Source,
   const SourceInfo &Loc = S.Current->getSource(OpPC);
   S.FFDiag(Loc, diag::note_constexpr_delete_not_heap_alloc)
       << Ptr.toDiagnosticString(S.getASTContext());
-
-  if (Ptr.isTemporary())
-    S.Note(Ptr.getDeclLoc(), diag::note_constexpr_temporary_here);
-  else
-    S.Note(Ptr.getDeclLoc(), diag::note_declared_at);
+  noteValueLocation(S, Ptr.block());
   return false;
 }
 
@@ -1505,7 +1513,7 @@ bool CheckDestructor(InterpState &S, CodePtr OpPC, const 
Pointer &Ptr) {
     return false;
   if (!CheckRange(S, OpPC, Ptr, AK_Destroy))
     return false;
-  if (!CheckLifetime(S, OpPC, Ptr.getLifetime(), AK_Destroy))
+  if (!CheckLifetime(S, OpPC, Ptr, AK_Destroy))
     return false;
 
   // Can't call a dtor on a global variable.
@@ -2028,7 +2036,7 @@ bool CheckNewTypeMismatch(InterpState &S, CodePtr OpPC, 
const Expr *E,
 
   // CheckLifetime for this and all base pointers.
   for (Pointer P = Ptr;;) {
-    if (!CheckLifetime(S, OpPC, P.getLifetime(), AK_Construct))
+    if (!CheckLifetime(S, OpPC, P, AK_Construct))
       return false;
 
     if (P.isRoot())
diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h
index 99651ca98ea6d..ea94df2c90187 100644
--- a/clang/lib/AST/ByteCode/Interp.h
+++ b/clang/lib/AST/ByteCode/Interp.h
@@ -82,7 +82,7 @@ bool CheckFinalLoad(InterpState &S, CodePtr OpPC, const 
Pointer &Ptr);
 bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, const Pointer &Ptr,
                            AccessKinds AK);
 bool DiagnoseUninitialized(InterpState &S, CodePtr OpPC, bool Extern,
-                           const Descriptor *Desc, AccessKinds AK);
+                           const Block *B, AccessKinds AK);
 
 /// Checks a direct load of a primitive value from a global or local variable.
 bool CheckGlobalLoad(InterpState &S, CodePtr OpPC, const Block *B);
@@ -1663,8 +1663,7 @@ bool GetGlobalUnchecked(InterpState &S, CodePtr OpPC, 
uint32_t I) {
   const Block *B = S.P.getGlobal(I);
   const auto &Desc = B->getBlockDesc<GlobalInlineDescriptor>();
   if (Desc.InitState != GlobalInitState::Initialized)
-    return DiagnoseUninitialized(S, OpPC, B->isExtern(), B->getDescriptor(),
-                                 AK_Read);
+    return DiagnoseUninitialized(S, OpPC, B->isExtern(), B, AK_Read);
 
   S.Stk.push<T>(B->deref<T>());
   return true;
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 4f45fa728c605..a185f1b631cf8 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -4180,10 +4180,12 @@ findSubobject(EvalInfo &Info, const Expr *E, const 
CompleteObject &Obj,
       // IsWithinLifetime, resulting in false.
       if (I != 0 && handler.AccessKind == AK_IsWithinLifetime)
         return false;
-      if (!Info.checkingPotentialConstantExpression())
+      if (!Info.checkingPotentialConstantExpression()) {
         Info.FFDiag(E, diag::note_constexpr_access_uninit)
             << handler.AccessKind << O->isIndeterminate()
             << E->getSourceRange();
+        NoteLValueLocation(Info, Obj.Base);
+      }
       return handler.failed();
     }
 
diff --git a/clang/test/AST/ByteCode/builtin-bit-cast-bitfields.cpp 
b/clang/test/AST/ByteCode/builtin-bit-cast-bitfields.cpp
index 5aa4e256e4638..2eefa138f7f0a 100644
--- a/clang/test/AST/ByteCode/builtin-bit-cast-bitfields.cpp
+++ b/clang/test/AST/ByteCode/builtin-bit-cast-bitfields.cpp
@@ -156,8 +156,9 @@ namespace BitFields {
 
     static_assert(f()[0] + f()[1] + f()[2] == 0xc0 + 0xff + 0xee);
     {
-      // expected-error@+2 {{initialized by a constant expression}}
-      // expected-note@+1 {{in call to}}
+      // expected-error@+3 {{initialized by a constant expression}}
+      // expected-note@+2 {{in call to}}
+      // expected-note@+1 {{temporary created here}}
       constexpr auto _bad = f()[3];
     }
 
@@ -173,8 +174,9 @@ namespace BitFields {
     };
     static_assert(g().s0 + g().s1 + g().b0 + g().b1 == 0xc0 + 0xff + 0xe + 
0xe);
     {
-      // expected-error@+2 {{initialized by a constant expression}}
-      // expected-note@+1 {{read of uninitialized object is not allowed in a 
constant expression}}
+      // expected-error@+3 {{initialized by a constant expression}}
+      // expected-note@+2 {{read of uninitialized object is not allowed in a 
constant expression}}
+      // expected-note@+1 {{temporary created here}}
       constexpr auto _bad = g().b2;
     }
   }
diff --git a/clang/test/AST/ByteCode/builtin-bit-cast-long-double.cpp 
b/clang/test/AST/ByteCode/builtin-bit-cast-long-double.cpp
index 1013a771d13b4..7e34c3ff9d755 100644
--- a/clang/test/AST/ByteCode/builtin-bit-cast-long-double.cpp
+++ b/clang/test/AST/ByteCode/builtin-bit-cast-long-double.cpp
@@ -61,7 +61,7 @@ constexpr long double foo() {
 static_assert(foo() == ld);
 
 constexpr bool f(bool read_uninit) {
-  bytes b = bit_cast<bytes>(ld);
+  bytes b = bit_cast<bytes>(ld); // both-note {{declared here}}
   unsigned char ld_bytes[10] = {
     0x0,  0x48, 0x9f, 0x49, 0xf0,
     0x3c, 0x20, 0xc9, 0x0,  0x40,
diff --git a/clang/test/AST/ByteCode/builtin-functions.cpp 
b/clang/test/AST/ByteCode/builtin-functions.cpp
index 93b6e06490e61..f423ef1c8b301 100644
--- a/clang/test/AST/ByteCode/builtin-functions.cpp
+++ b/clang/test/AST/ByteCode/builtin-functions.cpp
@@ -1216,7 +1216,7 @@ namespace shufflevector {
 #if __cplusplus >= 202002L
   constexpr int discarded3() {
     int i = 0;
-    vector4char a;
+    vector4char a; // both-note {{declared here}}
     __builtin_shufflevector((++i, a), a, 0); // both-note {{read of 
uninitialized object}} \
                                              // both-warning {{expression 
result unused}}
     return i;
diff --git a/clang/test/AST/ByteCode/constexpr-nqueens.cpp 
b/clang/test/AST/ByteCode/constexpr-nqueens.cpp
index ed038dbc9b077..63a3e63c3765c 100644
--- a/clang/test/AST/ByteCode/constexpr-nqueens.cpp
+++ b/clang/test/AST/ByteCode/constexpr-nqueens.cpp
@@ -60,7 +60,9 @@ constexpr Board buildBoardRecurse(int N, int Col, const Board 
&B) {
 }
 constexpr Board buildBoard(int N) {
   return buildBoardRecurse(N, 0, Board()); // ref-note {{in call to 
'buildBoardRecurse(8, 0, Board())'}} \
-                                           // expected-note {{in call to 
'buildBoardRecurse(8, 0, Board())'}}
+                                           // expected-note {{in call to 
'buildBoardRecurse(8, 0, Board())'}} \
+                                           // ref-note {{temporary created 
here}} \
+                                           // expected-note {{temporary 
created here}}
 }
 
 constexpr Board q8 = buildBoard(8); // ref-error {{must be initialized by a 
constant expression}} \
diff --git a/clang/test/AST/ByteCode/cxx11.cpp 
b/clang/test/AST/ByteCode/cxx11.cpp
index 668228e2dc166..a4c4be14775b3 100644
--- a/clang/test/AST/ByteCode/cxx11.cpp
+++ b/clang/test/AST/ByteCode/cxx11.cpp
@@ -24,7 +24,8 @@ int array2[recurse2]; // both-warning {{variable length 
arrays in C++}} \
                       // ref-warning {{variable length array folded to 
constant array as an extension}}
 
 constexpr int b = b; // both-error {{must be initialized by a constant 
expression}} \
-                     // both-note {{read of object outside its lifetime is not 
allowed in a constant expression}}
+                     // both-note {{read of object outside its lifetime is not 
allowed in a constant expression}} \
+                     // both-note {{declared here}}
 
 
 [[clang::require_constant_initialization]] int c = c; // both-error {{variable 
does not have a constant initializer}} \
diff --git a/clang/test/AST/ByteCode/cxx17.cpp 
b/clang/test/AST/ByteCode/cxx17.cpp
index 583d9879ad245..166638b0f5211 100644
--- a/clang/test/AST/ByteCode/cxx17.cpp
+++ b/clang/test/AST/ByteCode/cxx17.cpp
@@ -3,7 +3,8 @@
 
 [[clang::require_constant_initialization]] int cc = cc; // both-error 
{{variable does not have a constant initializer}} \
                                                         // both-note 
{{attribute here}} \
-                                                        // both-note {{ead of 
object outside its lifetime}}
+                                                        // both-note {{ead of 
object outside its lifetime}} \
+                                                        // both-note 
{{declared here}}
 
 
 struct F { int a; int b;};
diff --git a/clang/test/AST/ByteCode/cxx20.cpp 
b/clang/test/AST/ByteCode/cxx20.cpp
index 9800fe01fcaf5..27ba0349d634e 100644
--- a/clang/test/AST/ByteCode/cxx20.cpp
+++ b/clang/test/AST/ByteCode/cxx20.cpp
@@ -57,7 +57,7 @@ constexpr int pointerAssign2() {
 static_assert(pointerAssign2() == 12, "");
 
 constexpr int unInitLocal() {
-  int a;
+  int a; // both-note {{declared here}}
   return a; // both-note {{read of uninitialized object}}
 }
 static_assert(unInitLocal() == 0, ""); // both-error {{not an integral 
constant expression}} \
@@ -71,7 +71,7 @@ constexpr int initializedLocal() {
 static_assert(initializedLocal() == 20);
 
 constexpr int initializedLocal2() {
-  int a[2];
+  int a[2]; // both-note {{declared here}}
   return *a; // both-note {{read of uninitialized object is not allowed in a 
constant expression}}
 }
 static_assert(initializedLocal2() == 20); // both-error {{not an integral 
constant expression}} \
@@ -80,7 +80,7 @@ static_assert(initializedLocal2() == 20); // both-error {{not 
an integral consta
 
 struct Int { int a; };
 constexpr int initializedLocal3() {
-  Int i;
+  Int i; // both-note {{declared here}}
   return i.a; // both-note {{read of uninitialized object is not allowed in a 
constant expression}}
 }
 static_assert(initializedLocal3() == 20); // both-error {{not an integral 
constant expression}} \
@@ -274,7 +274,8 @@ namespace BaseInit {
 
   static_assert(Final{1, 2, 3}.c == 3, ""); // OK
   static_assert(Final{1, 2, 3}.a == 0, ""); // both-error {{not an integral 
constant expression}} \
-                                            // both-note {{read of 
uninitialized object}}
+                                            // both-note {{read of 
uninitialized object}} \
+                                            // both-note {{temporary created 
here}}
 
 
   struct Mixin  {
@@ -294,7 +295,8 @@ namespace BaseInit {
   static_assert(Final2{1, 2, 3}.c == 3, ""); // OK
   static_assert(Final2{1, 2, 3}.b == 2, ""); // OK
   static_assert(Final2{1, 2, 3}.a == 0, ""); // both-error {{not an integral 
constant expression}} \
-                                             // both-note {{read of 
uninitialized object}}
+                                             // both-note {{read of 
uninitialized object}} \
+                                             // both-note {{temporary created 
here}}
 
 
   struct Mixin3  {
@@ -311,7 +313,8 @@ namespace BaseInit {
   static_assert(Final3{1, 2, 3}.c == 3, ""); // OK
   static_assert(Final3{1, 2, 3}.b == 2, ""); // OK
   static_assert(Final3{1, 2, 3}.a == 0, ""); // both-error {{not an integral 
constant expression}} \
-                                             // both-note {{read of 
uninitialized object}}
+                                             // both-note {{read of 
uninitialized object}} \
+                                             // both-note {{temporary created 
here}}
 };
 
 namespace Destructors {
@@ -584,7 +587,7 @@ namespace ImplicitFunction {
   };
 
   constexpr int callMe() {
-   A a;
+   A a; // expected-note {{declared here}}
    A b{12};
 
    /// The operator= call here will fail and the diagnostics should be fine.
@@ -969,7 +972,7 @@ namespace LocalDestroy {
 namespace PseudoDtor {
   constexpr int f1() {
    using T = int;
-   int a = 0;
+   int a = 0; // both-note {{declared here}}
    a.~T();
    return a; // both-note {{read of object outside its lifetime}}
   }
@@ -978,7 +981,7 @@ namespace PseudoDtor {
 
   constexpr int f2() {
    using T = int;
-   int a = 0;
+   int a = 0; // both-note {{declared here}}
    a.~T();
    a = 0; // both-note {{assignment to object outside its lifetime}}
    return a;
diff --git a/clang/test/AST/ByteCode/cxx2a.cpp 
b/clang/test/AST/ByteCode/cxx2a.cpp
index 533173d84792f..78769a4def5b0 100644
--- a/clang/test/AST/ByteCode/cxx2a.cpp
+++ b/clang/test/AST/ByteCode/cxx2a.cpp
@@ -210,7 +210,8 @@ namespace PureVirtual {
 namespace Dtor {
   constexpr bool pseudo(bool read, bool recreate) {
     using T = bool;
-    bool b = false; // both-note {{lifetime has already ended}}
+    bool b = false; // both-note {{lifetime has already ended}} \
+                    // both-note {{declared here}}
     // This evaluates the store to 'b'...
     (b = true).~T();
     // ... and ends the lifetime of the object.
diff --git a/clang/test/AST/ByteCode/lifetimes.cpp 
b/clang/test/AST/ByteCode/lifetimes.cpp
index 96c868209c5b2..e775bed751821 100644
--- a/clang/test/AST/ByteCode/lifetimes.cpp
+++ b/clang/test/AST/ByteCode/lifetimes.cpp
@@ -11,7 +11,7 @@ constexpr int dead1() {
 
   Foo *F2 = nullptr;
   {
-    Foo F{12}; // expected-note {{declared here}}
+    Foo F{12}; // both-note {{declared here}}
     F2 = &F;
   } // Ends lifetime of F.
 
@@ -27,7 +27,7 @@ struct S {
   int t;
   constexpr S() : r(0), t(r) {} // both-error {{reference member 'r' binds to 
a temporary object whose lifetime would be shorter than the lifetime of the 
constructed object}} \
                                 // both-note {{read of object outside its 
lifetime is not allowed in a constant expression}} \
-                                // expected-note {{temporary created here}}
+                                // both-note {{temporary created here}}
 };
 constexpr int k1 = S().t; // both-error {{must be initialized by a constant 
expression}} \
 ...
[truncated]

``````````

</details>


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

Reply via email to