https://github.com/nickdesaulniers updated 
https://github.com/llvm/llvm-project/pull/219045

>From 83e4a08a86b398b6e3f766b2ee32b460e487859d Mon Sep 17 00:00:00 2001
From: Nick Desaulniers <[email protected]>
Date: Wed, 26 Aug 2026 13:41:55 -0700
Subject: [PATCH] [clang][CodeGen] Emit lifetime markers for block-scoped
 compound literals in C
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

In C (C99/C11/C23 ยง6.2.4.5), block-scoped compound literals have
automatic storage duration extending to the end of the enclosing block
scope.  Previously, Clang emitted alloca storage without lifetime
markers (@llvm.lifetime.start / @llvm.lifetime.end), preventing LLVM's
StackColoring pass from merging stack slots across disjoint scopes and
inflating stack frame size.

Following John McCall's guidance in #68746:
1. In Sema, record block-scoped compound literals in ExprCleanupObjects so
   the enclosing full-expression is wrapped in an ExprWithCleanups.
2. In CodeGen, emit @llvm.lifetime.start before evaluating initializers and
   schedule CallLifetimeEnd as a cleanup.

Checking a build of an x86_64 Linux kernel defconfig build, this shaves
448 bytes off the stack usage for azx_probe(), one of the larger stack
users in the kernel.

Assisted-by: Gemini
Fixes: https://github.com/llvm/llvm-project/issues/68746
---
 clang/lib/CodeGen/CGExpr.cpp                  |   7 +
 clang/lib/Sema/JumpDiagnostics.cpp            |   2 +
 clang/lib/Sema/SemaExpr.cpp                   |   4 +-
 clang/test/AST/ast-dump-expr-json.c           | 226 +++++++++++-------
 clang/test/C/C11/n1285_1.c                    |   2 +
 .../CodeGen/attr-counted-by-with-sanitizers.c |  10 +-
 .../attr-counted-by-without-sanitizers.c      |   4 +
 .../test/CodeGen/compound-literal-lifetime.c  |  93 +++++++
 clang/test/CodeGenObjC/arc-ternary-op.m       |   2 +
 clang/test/Sema/scope-check.c                 |  14 ++
 10 files changed, 274 insertions(+), 90 deletions(-)
 create mode 100644 clang/test/CodeGen/compound-literal-lifetime.c

diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index eff6a7de320d7..19700d2fcf665 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -6005,6 +6005,13 @@ LValue CodeGenFunction::EmitCompoundLiteralLValue(const 
CompoundLiteralExpr *E){
   const Expr *InitExpr = E->getInitializer();
   LValue Result = MakeAddrLValue(DeclPtr, E->getType(), AlignmentSource::Decl);
 
+  if (!getLangOpts().CPlusPlus) {
+    if (HaveInsertPoint() && !hasLabelBeenSeenInCurrentScope() &&
+        EmitLifetimeStart(DeclPtr.getBasePointer()))
+      pushCleanupAfterFullExpr<CallLifetimeEnd>(NormalEHLifetimeMarker,
+                                                DeclPtr);
+  }
+
   EmitAnyExprToMem(InitExpr, DeclPtr, E->getType().getQualifiers(),
                    /*Init*/ true);
 
diff --git a/clang/lib/Sema/JumpDiagnostics.cpp 
b/clang/lib/Sema/JumpDiagnostics.cpp
index b4a9cc12029d2..bbe6f644609bf 100644
--- a/clang/lib/Sema/JumpDiagnostics.cpp
+++ b/clang/lib/Sema/JumpDiagnostics.cpp
@@ -293,6 +293,8 @@ void JumpScopeChecker::BuildScopeInformation(VarDecl *D,
 /// non-trivial to destruct.
 void JumpScopeChecker::BuildScopeInformation(CompoundLiteralExpr *CLE,
                                              unsigned &ParentScope) {
+  if (!CLE->getType().isDestructedType())
+    return;
   unsigned InDiag = diag::note_enters_compound_literal_scope;
   unsigned OutDiag = diag::note_exits_compound_literal_scope;
   Scopes.push_back(GotoScope(ParentScope, InDiag, OutDiag, CLE->getExprLoc()));
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 2b524a956ecc4..48d80f5fd7ae8 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -7578,9 +7578,9 @@ Sema::BuildCompoundLiteralExpr(SourceLocation LParenLoc, 
TypeSourceInfo *TInfo,
                             NTCUK_Destruct);
 
     // Diagnose jumps that enter or exit the lifetime of the compound literal.
+    Cleanup.setExprNeedsCleanups(true);
+    ExprCleanupObjects.push_back(E);
     if (literalType.isDestructedType()) {
-      Cleanup.setExprNeedsCleanups(true);
-      ExprCleanupObjects.push_back(E);
       getCurFunction()->setHasBranchProtectedScope();
     }
   }
diff --git a/clang/test/AST/ast-dump-expr-json.c 
b/clang/test/AST/ast-dump-expr-json.c
index ecb6191c52200..48a6f19b55371 100644
--- a/clang/test/AST/ast-dump-expr-json.c
+++ b/clang/test/AST/ast-dump-expr-json.c
@@ -4650,7 +4650,7 @@ void PrimaryExpressions(int a) {
 // CHECK-NEXT:     },
 // CHECK-NEXT:     {
 // CHECK-NEXT:      "id": "0x{{.*}}",
-// CHECK-NEXT:      "kind": "ImplicitCastExpr",
+// CHECK-NEXT:      "kind": "ExprWithCleanups",
 // CHECK-NEXT:      "range": {
 // CHECK-NEXT:       "begin": {
 // CHECK-NEXT:        "offset": {{[0-9]+}},
@@ -4668,11 +4668,17 @@ void PrimaryExpressions(int a) {
 // CHECK-NEXT:       "qualType": "int *"
 // CHECK-NEXT:      },
 // CHECK-NEXT:      "valueCategory": "prvalue",
-// CHECK-NEXT:      "castKind": "ArrayToPointerDecay",
+// CHECK-NEXT:      "cleanupsHaveSideEffects": true,
+// CHECK-NEXT:      "cleanups": [
+// CHECK-NEXT:       {
+// CHECK-NEXT:        "id": "0x{{.*}}",
+// CHECK-NEXT:        "kind": "CompoundLiteralExpr"
+// CHECK-NEXT:       }
+// CHECK-NEXT:      ],
 // CHECK-NEXT:      "inner": [
 // CHECK-NEXT:       {
 // CHECK-NEXT:        "id": "0x{{.*}}",
-// CHECK-NEXT:        "kind": "CompoundLiteralExpr",
+// CHECK-NEXT:        "kind": "ImplicitCastExpr",
 // CHECK-NEXT:        "range": {
 // CHECK-NEXT:         "begin": {
 // CHECK-NEXT:          "offset": {{[0-9]+}},
@@ -4686,17 +4692,18 @@ void PrimaryExpressions(int a) {
 // CHECK-NEXT:         }
 // CHECK-NEXT:        },
 // CHECK-NEXT:        "type": {
-// CHECK-NEXT:         "qualType": "int[4]"
+// CHECK-NEXT:         "qualType": "int *"
 // CHECK-NEXT:        },
-// CHECK-NEXT:        "valueCategory": "lvalue",
+// CHECK-NEXT:        "valueCategory": "prvalue",
+// CHECK-NEXT:        "castKind": "ArrayToPointerDecay",
 // CHECK-NEXT:        "inner": [
 // CHECK-NEXT:         {
 // CHECK-NEXT:          "id": "0x{{.*}}",
-// CHECK-NEXT:          "kind": "InitListExpr",
+// CHECK-NEXT:          "kind": "CompoundLiteralExpr",
 // CHECK-NEXT:          "range": {
 // CHECK-NEXT:           "begin": {
 // CHECK-NEXT:            "offset": {{[0-9]+}},
-// CHECK-NEXT:            "col": 12,
+// CHECK-NEXT:            "col": 3,
 // CHECK-NEXT:            "tokLen": 1
 // CHECK-NEXT:           },
 // CHECK-NEXT:           "end": {
@@ -4708,91 +4715,113 @@ void PrimaryExpressions(int a) {
 // CHECK-NEXT:          "type": {
 // CHECK-NEXT:           "qualType": "int[4]"
 // CHECK-NEXT:          },
-// CHECK-NEXT:          "valueCategory": "prvalue",
+// CHECK-NEXT:          "valueCategory": "lvalue",
 // CHECK-NEXT:          "inner": [
 // CHECK-NEXT:           {
 // CHECK-NEXT:            "id": "0x{{.*}}",
-// CHECK-NEXT:            "kind": "IntegerLiteral",
+// CHECK-NEXT:            "kind": "InitListExpr",
 // CHECK-NEXT:            "range": {
 // CHECK-NEXT:             "begin": {
 // CHECK-NEXT:              "offset": {{[0-9]+}},
-// CHECK-NEXT:              "col": 13,
+// CHECK-NEXT:              "col": 12,
 // CHECK-NEXT:              "tokLen": 1
 // CHECK-NEXT:             },
 // CHECK-NEXT:             "end": {
 // CHECK-NEXT:              "offset": {{[0-9]+}},
-// CHECK-NEXT:              "col": 13,
+// CHECK-NEXT:              "col": 25,
 // CHECK-NEXT:              "tokLen": 1
 // CHECK-NEXT:             }
 // CHECK-NEXT:            },
 // CHECK-NEXT:            "type": {
-// CHECK-NEXT:             "qualType": "int"
+// CHECK-NEXT:             "qualType": "int[4]"
 // CHECK-NEXT:            },
 // CHECK-NEXT:            "valueCategory": "prvalue",
-// CHECK-NEXT:            "value": "1"
-// CHECK-NEXT:           },
-// CHECK-NEXT:           {
-// CHECK-NEXT:            "id": "0x{{.*}}",
-// CHECK-NEXT:            "kind": "IntegerLiteral",
-// CHECK-NEXT:            "range": {
-// CHECK-NEXT:             "begin": {
-// CHECK-NEXT:              "offset": {{[0-9]+}},
-// CHECK-NEXT:              "col": 16,
-// CHECK-NEXT:              "tokLen": 1
+// CHECK-NEXT:            "inner": [
+// CHECK-NEXT:             {
+// CHECK-NEXT:              "id": "0x{{.*}}",
+// CHECK-NEXT:              "kind": "IntegerLiteral",
+// CHECK-NEXT:              "range": {
+// CHECK-NEXT:               "begin": {
+// CHECK-NEXT:                "offset": {{[0-9]+}},
+// CHECK-NEXT:                "col": 13,
+// CHECK-NEXT:                "tokLen": 1
+// CHECK-NEXT:               },
+// CHECK-NEXT:               "end": {
+// CHECK-NEXT:                "offset": {{[0-9]+}},
+// CHECK-NEXT:                "col": 13,
+// CHECK-NEXT:                "tokLen": 1
+// CHECK-NEXT:               }
+// CHECK-NEXT:              },
+// CHECK-NEXT:              "type": {
+// CHECK-NEXT:               "qualType": "int"
+// CHECK-NEXT:              },
+// CHECK-NEXT:              "valueCategory": "prvalue",
+// CHECK-NEXT:              "value": "1"
 // CHECK-NEXT:             },
-// CHECK-NEXT:             "end": {
-// CHECK-NEXT:              "offset": {{[0-9]+}},
-// CHECK-NEXT:              "col": 16,
-// CHECK-NEXT:              "tokLen": 1
-// CHECK-NEXT:             }
-// CHECK-NEXT:            },
-// CHECK-NEXT:            "type": {
-// CHECK-NEXT:             "qualType": "int"
-// CHECK-NEXT:            },
-// CHECK-NEXT:            "valueCategory": "prvalue",
-// CHECK-NEXT:            "value": "2"
-// CHECK-NEXT:           },
-// CHECK-NEXT:           {
-// CHECK-NEXT:            "id": "0x{{.*}}",
-// CHECK-NEXT:            "kind": "IntegerLiteral",
-// CHECK-NEXT:            "range": {
-// CHECK-NEXT:             "begin": {
-// CHECK-NEXT:              "offset": {{[0-9]+}},
-// CHECK-NEXT:              "col": 19,
-// CHECK-NEXT:              "tokLen": 1
+// CHECK-NEXT:             {
+// CHECK-NEXT:              "id": "0x{{.*}}",
+// CHECK-NEXT:              "kind": "IntegerLiteral",
+// CHECK-NEXT:              "range": {
+// CHECK-NEXT:               "begin": {
+// CHECK-NEXT:                "offset": {{[0-9]+}},
+// CHECK-NEXT:                "col": 16,
+// CHECK-NEXT:                "tokLen": 1
+// CHECK-NEXT:               },
+// CHECK-NEXT:               "end": {
+// CHECK-NEXT:                "offset": {{[0-9]+}},
+// CHECK-NEXT:                "col": 16,
+// CHECK-NEXT:                "tokLen": 1
+// CHECK-NEXT:               }
+// CHECK-NEXT:              },
+// CHECK-NEXT:              "type": {
+// CHECK-NEXT:               "qualType": "int"
+// CHECK-NEXT:              },
+// CHECK-NEXT:              "valueCategory": "prvalue",
+// CHECK-NEXT:              "value": "2"
 // CHECK-NEXT:             },
-// CHECK-NEXT:             "end": {
-// CHECK-NEXT:              "offset": {{[0-9]+}},
-// CHECK-NEXT:              "col": 19,
-// CHECK-NEXT:              "tokLen": 1
-// CHECK-NEXT:             }
-// CHECK-NEXT:            },
-// CHECK-NEXT:            "type": {
-// CHECK-NEXT:             "qualType": "int"
-// CHECK-NEXT:            },
-// CHECK-NEXT:            "valueCategory": "prvalue",
-// CHECK-NEXT:            "value": "3"
-// CHECK-NEXT:           },
-// CHECK-NEXT:           {
-// CHECK-NEXT:            "id": "0x{{.*}}",
-// CHECK-NEXT:            "kind": "IntegerLiteral",
-// CHECK-NEXT:            "range": {
-// CHECK-NEXT:             "begin": {
-// CHECK-NEXT:              "offset": {{[0-9]+}},
-// CHECK-NEXT:              "col": 22,
-// CHECK-NEXT:              "tokLen": 1
+// CHECK-NEXT:             {
+// CHECK-NEXT:              "id": "0x{{.*}}",
+// CHECK-NEXT:              "kind": "IntegerLiteral",
+// CHECK-NEXT:              "range": {
+// CHECK-NEXT:               "begin": {
+// CHECK-NEXT:                "offset": {{[0-9]+}},
+// CHECK-NEXT:                "col": 19,
+// CHECK-NEXT:                "tokLen": 1
+// CHECK-NEXT:               },
+// CHECK-NEXT:               "end": {
+// CHECK-NEXT:                "offset": {{[0-9]+}},
+// CHECK-NEXT:                "col": 19,
+// CHECK-NEXT:                "tokLen": 1
+// CHECK-NEXT:               }
+// CHECK-NEXT:              },
+// CHECK-NEXT:              "type": {
+// CHECK-NEXT:               "qualType": "int"
+// CHECK-NEXT:              },
+// CHECK-NEXT:              "valueCategory": "prvalue",
+// CHECK-NEXT:              "value": "3"
 // CHECK-NEXT:             },
-// CHECK-NEXT:             "end": {
-// CHECK-NEXT:              "offset": {{[0-9]+}},
-// CHECK-NEXT:              "col": 22,
-// CHECK-NEXT:              "tokLen": 1
+// CHECK-NEXT:             {
+// CHECK-NEXT:              "id": "0x{{.*}}",
+// CHECK-NEXT:              "kind": "IntegerLiteral",
+// CHECK-NEXT:              "range": {
+// CHECK-NEXT:               "begin": {
+// CHECK-NEXT:                "offset": {{[0-9]+}},
+// CHECK-NEXT:                "col": 22,
+// CHECK-NEXT:                "tokLen": 1
+// CHECK-NEXT:               },
+// CHECK-NEXT:               "end": {
+// CHECK-NEXT:                "offset": {{[0-9]+}},
+// CHECK-NEXT:                "col": 22,
+// CHECK-NEXT:                "tokLen": 1
+// CHECK-NEXT:               }
+// CHECK-NEXT:              },
+// CHECK-NEXT:              "type": {
+// CHECK-NEXT:               "qualType": "int"
+// CHECK-NEXT:              },
+// CHECK-NEXT:              "valueCategory": "prvalue",
+// CHECK-NEXT:              "value": "4"
 // CHECK-NEXT:             }
-// CHECK-NEXT:            },
-// CHECK-NEXT:            "type": {
-// CHECK-NEXT:             "qualType": "int"
-// CHECK-NEXT:            },
-// CHECK-NEXT:            "valueCategory": "prvalue",
-// CHECK-NEXT:            "value": "4"
+// CHECK-NEXT:            ]
 // CHECK-NEXT:           }
 // CHECK-NEXT:          ]
 // CHECK-NEXT:         }
@@ -4802,7 +4831,7 @@ void PrimaryExpressions(int a) {
 // CHECK-NEXT:     },
 // CHECK-NEXT:     {
 // CHECK-NEXT:      "id": "0x{{.*}}",
-// CHECK-NEXT:      "kind": "ImplicitCastExpr",
+// CHECK-NEXT:      "kind": "ExprWithCleanups",
 // CHECK-NEXT:      "range": {
 // CHECK-NEXT:       "begin": {
 // CHECK-NEXT:        "offset": {{[0-9]+}},
@@ -4820,11 +4849,17 @@ void PrimaryExpressions(int a) {
 // CHECK-NEXT:       "qualType": "struct S"
 // CHECK-NEXT:      },
 // CHECK-NEXT:      "valueCategory": "prvalue",
-// CHECK-NEXT:      "castKind": "LValueToRValue",
+// CHECK-NEXT:      "cleanupsHaveSideEffects": true,
+// CHECK-NEXT:      "cleanups": [
+// CHECK-NEXT:       {
+// CHECK-NEXT:        "id": "0x{{.*}}",
+// CHECK-NEXT:        "kind": "CompoundLiteralExpr"
+// CHECK-NEXT:       }
+// CHECK-NEXT:      ],
 // CHECK-NEXT:      "inner": [
 // CHECK-NEXT:       {
 // CHECK-NEXT:        "id": "0x{{.*}}",
-// CHECK-NEXT:        "kind": "CompoundLiteralExpr",
+// CHECK-NEXT:        "kind": "ImplicitCastExpr",
 // CHECK-NEXT:        "range": {
 // CHECK-NEXT:         "begin": {
 // CHECK-NEXT:          "offset": {{[0-9]+}},
@@ -4840,15 +4875,16 @@ void PrimaryExpressions(int a) {
 // CHECK-NEXT:        "type": {
 // CHECK-NEXT:         "qualType": "struct S"
 // CHECK-NEXT:        },
-// CHECK-NEXT:        "valueCategory": "lvalue",
+// CHECK-NEXT:        "valueCategory": "prvalue",
+// CHECK-NEXT:        "castKind": "LValueToRValue",
 // CHECK-NEXT:        "inner": [
 // CHECK-NEXT:         {
 // CHECK-NEXT:          "id": "0x{{.*}}",
-// CHECK-NEXT:          "kind": "InitListExpr",
+// CHECK-NEXT:          "kind": "CompoundLiteralExpr",
 // CHECK-NEXT:          "range": {
 // CHECK-NEXT:           "begin": {
 // CHECK-NEXT:            "offset": {{[0-9]+}},
-// CHECK-NEXT:            "col": 13,
+// CHECK-NEXT:            "col": 3,
 // CHECK-NEXT:            "tokLen": 1
 // CHECK-NEXT:           },
 // CHECK-NEXT:           "end": {
@@ -4860,28 +4896,50 @@ void PrimaryExpressions(int a) {
 // CHECK-NEXT:          "type": {
 // CHECK-NEXT:           "qualType": "struct S"
 // CHECK-NEXT:          },
-// CHECK-NEXT:          "valueCategory": "prvalue",
+// CHECK-NEXT:          "valueCategory": "lvalue",
 // CHECK-NEXT:          "inner": [
 // CHECK-NEXT:           {
 // CHECK-NEXT:            "id": "0x{{.*}}",
-// CHECK-NEXT:            "kind": "IntegerLiteral",
+// CHECK-NEXT:            "kind": "InitListExpr",
 // CHECK-NEXT:            "range": {
 // CHECK-NEXT:             "begin": {
 // CHECK-NEXT:              "offset": {{[0-9]+}},
-// CHECK-NEXT:              "col": 14,
+// CHECK-NEXT:              "col": 13,
 // CHECK-NEXT:              "tokLen": 1
 // CHECK-NEXT:             },
 // CHECK-NEXT:             "end": {
 // CHECK-NEXT:              "offset": {{[0-9]+}},
-// CHECK-NEXT:              "col": 14,
+// CHECK-NEXT:              "col": 15,
 // CHECK-NEXT:              "tokLen": 1
 // CHECK-NEXT:             }
 // CHECK-NEXT:            },
 // CHECK-NEXT:            "type": {
-// CHECK-NEXT:             "qualType": "int"
+// CHECK-NEXT:             "qualType": "struct S"
 // CHECK-NEXT:            },
 // CHECK-NEXT:            "valueCategory": "prvalue",
-// CHECK-NEXT:            "value": "1"
+// CHECK-NEXT:            "inner": [
+// CHECK-NEXT:             {
+// CHECK-NEXT:              "id": "0x{{.*}}",
+// CHECK-NEXT:              "kind": "IntegerLiteral",
+// CHECK-NEXT:              "range": {
+// CHECK-NEXT:               "begin": {
+// CHECK-NEXT:                "offset": {{[0-9]+}},
+// CHECK-NEXT:                "col": 14,
+// CHECK-NEXT:                "tokLen": 1
+// CHECK-NEXT:               },
+// CHECK-NEXT:               "end": {
+// CHECK-NEXT:                "offset": {{[0-9]+}},
+// CHECK-NEXT:                "col": 14,
+// CHECK-NEXT:                "tokLen": 1
+// CHECK-NEXT:               }
+// CHECK-NEXT:              },
+// CHECK-NEXT:              "type": {
+// CHECK-NEXT:               "qualType": "int"
+// CHECK-NEXT:              },
+// CHECK-NEXT:              "valueCategory": "prvalue",
+// CHECK-NEXT:              "value": "1"
+// CHECK-NEXT:             }
+// CHECK-NEXT:            ]
 // CHECK-NEXT:           }
 // CHECK-NEXT:          ]
 // CHECK-NEXT:         }
diff --git a/clang/test/C/C11/n1285_1.c b/clang/test/C/C11/n1285_1.c
index ddf00c99fda92..37044ca0f02d5 100644
--- a/clang/test/C/C11/n1285_1.c
+++ b/clang/test/C/C11/n1285_1.c
@@ -94,6 +94,7 @@ int func_return(void) {
 // C11-O2-NEXT:    store ptr [[ARRAYDECAY]], ptr @p, align 8, !tbaa 
[[INTPTR_TBAA6]]
 // C11-O2-NEXT:    call void @llvm.lifetime.end.p0(ptr [[REF_TMP]]) #[[ATTR4]]
 // C11-O2-NEXT:    call void @llvm.lifetime.start.p0(ptr [[Q]]) #[[ATTR4]]
+// C11-O2-NEXT:    call void @llvm.lifetime.start.p0(ptr 
[[DOTCOMPOUNDLITERAL]]) #[[ATTR4]]
 // C11-O2-NEXT:    call void @llvm.memset.p0.i64(ptr align 4 
[[DOTCOMPOUNDLITERAL]], i8 0, i64 20, i1 false)
 // C11-O2-NEXT:    [[A2:%.*]] = getelementptr inbounds nuw [[STRUCT_X]], ptr 
[[DOTCOMPOUNDLITERAL]], i32 0, i32 0
 // C11-O2-NEXT:    [[A3:%.*]] = getelementptr inbounds nuw [[STRUCT_X]], ptr 
[[DOTCOMPOUNDLITERAL]], i32 0, i32 0
@@ -104,6 +105,7 @@ int func_return(void) {
 // C11-O2-NEXT:    [[TMP2:%.*]] = load ptr, ptr [[Q]], align 8, !tbaa 
[[INTPTR_TBAA6]]
 // C11-O2-NEXT:    [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4, !tbaa 
[[INT_TBAA9]]
 // C11-O2-NEXT:    [[ADD:%.*]] = add nsw i32 [[TMP1]], [[TMP3]]
+// C11-O2-NEXT:    call void @llvm.lifetime.end.p0(ptr [[DOTCOMPOUNDLITERAL]]) 
#[[ATTR4]]
 // C11-O2-NEXT:    call void @llvm.lifetime.end.p0(ptr [[Q]]) #[[ATTR4]]
 // C11-O2-NEXT:    ret i32 [[ADD]]
 //
diff --git a/clang/test/CodeGen/attr-counted-by-with-sanitizers.c 
b/clang/test/CodeGen/attr-counted-by-with-sanitizers.c
index e840db632957e..576a61171c253 100644
--- a/clang/test/CodeGen/attr-counted-by-with-sanitizers.c
+++ b/clang/test/CodeGen/attr-counted-by-with-sanitizers.c
@@ -529,12 +529,12 @@ size_t test_return_bdos_of_anon_struct(struct 
union_of_fams *p) {
 // SANITIZE-WITH-ATTR-NEXT:    [[COUNTED_BY_LOAD:%.*]] = load i8, ptr 
[[TMP0]], align 4
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = zext i8 [[COUNTED_BY_LOAD]] to 
i32, !nosanitize [[META6]]
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP2:%.*]] = icmp ult i32 [[INDEX]], 
[[TMP1]], !nosanitize [[META6]]
-// SANITIZE-WITH-ATTR-NEXT:    br i1 [[TMP2]], label %[[CONT14:.*]], label 
%[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7]], !nosanitize [[META6]]
+// SANITIZE-WITH-ATTR-NEXT:    br i1 [[TMP2]], label %[[CONT16:.*]], label 
%[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7]], !nosanitize [[META6]]
 // SANITIZE-WITH-ATTR:       [[HANDLER_OUT_OF_BOUNDS]]:
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP3:%.*]] = zext i32 [[INDEX]] to i64, 
!nosanitize [[META6]]
 // SANITIZE-WITH-ATTR-NEXT:    tail call void 
@__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB16:[0-9]+]], i64 
[[TMP3]]) #[[ATTR7]], !nosanitize [[META6]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META6]]
-// SANITIZE-WITH-ATTR:       [[CONT14]]:
+// SANITIZE-WITH-ATTR:       [[CONT16]]:
 // SANITIZE-WITH-ATTR-NEXT:    [[INTS:%.*]] = getelementptr inbounds nuw i8, 
ptr [[P]], i64 9
 // SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM:%.*]] = zext nneg i32 [[INDEX]] to i64
 // SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds nuw 
i8, ptr [[INTS]], i64 [[IDXPROM]]
@@ -612,12 +612,12 @@ void test_assign_bdos_of_struct_to_union_fam(struct 
union_of_fams *p, int index)
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP1:%.*]] = icmp ult i32 [[INDEX]], 
[[COUNTED_BY_LOAD]], !nosanitize [[META6]]
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP2:%.*]] = icmp sgt i32 
[[COUNTED_BY_LOAD]], 0, !nosanitize [[META6]]
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP3:%.*]] = and i1 [[TMP2]], [[TMP1]], 
!nosanitize [[META6]]
-// SANITIZE-WITH-ATTR-NEXT:    br i1 [[TMP3]], label %[[CONT14:.*]], label 
%[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7]], !nosanitize [[META6]]
+// SANITIZE-WITH-ATTR-NEXT:    br i1 [[TMP3]], label %[[CONT16:.*]], label 
%[[HANDLER_OUT_OF_BOUNDS:.*]], !prof [[PROF7]], !nosanitize [[META6]]
 // SANITIZE-WITH-ATTR:       [[HANDLER_OUT_OF_BOUNDS]]:
 // SANITIZE-WITH-ATTR-NEXT:    [[TMP4:%.*]] = zext i32 [[INDEX]] to i64, 
!nosanitize [[META6]]
 // SANITIZE-WITH-ATTR-NEXT:    tail call void 
@__ubsan_handle_out_of_bounds_abort(ptr nonnull @[[GLOB19:[0-9]+]], i64 
[[TMP4]]) #[[ATTR7]], !nosanitize [[META6]]
 // SANITIZE-WITH-ATTR-NEXT:    unreachable, !nosanitize [[META6]]
-// SANITIZE-WITH-ATTR:       [[CONT14]]:
+// SANITIZE-WITH-ATTR:       [[CONT16]]:
 // SANITIZE-WITH-ATTR-NEXT:    [[BYTES:%.*]] = getelementptr inbounds nuw i8, 
ptr [[P]], i64 12
 // SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[INDEX]] to i64
 // SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i8, 
ptr [[BYTES]], i64 [[IDXPROM]]
@@ -852,6 +852,7 @@ struct compound_literal {
 // SANITIZE-WITH-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr 
#[[ATTR3]] {
 // SANITIZE-WITH-ATTR-NEXT:  [[ENTRY:.*:]]
 // SANITIZE-WITH-ATTR-NEXT:    [[DOTCOMPOUNDLITERAL:%.*]] = alloca 
[[STRUCT_COMPOUND_LITERAL:%.*]], align 4
+// SANITIZE-WITH-ATTR-NEXT:    call void @llvm.lifetime.start.p0(ptr nonnull 
[[DOTCOMPOUNDLITERAL]]) #[[ATTR8]]
 // SANITIZE-WITH-ATTR-NEXT:    store i32 1, ptr [[DOTCOMPOUNDLITERAL]], align 
4, !tbaa [[INT_TBAA8]]
 // SANITIZE-WITH-ATTR-NEXT:    [[Y:%.*]] = getelementptr inbounds nuw i8, ptr 
[[DOTCOMPOUNDLITERAL]], i64 4
 // SANITIZE-WITH-ATTR-NEXT:    store i32 2, ptr [[Y]], align 4, !tbaa 
[[INT_TBAA8]]
@@ -871,6 +872,7 @@ struct compound_literal {
 // SANITIZE-WITHOUT-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr 
#[[ATTR3]] {
 // SANITIZE-WITHOUT-ATTR-NEXT:  [[ENTRY:.*:]]
 // SANITIZE-WITHOUT-ATTR-NEXT:    [[DOTCOMPOUNDLITERAL:%.*]] = alloca 
[[STRUCT_COMPOUND_LITERAL:%.*]], align 4
+// SANITIZE-WITHOUT-ATTR-NEXT:    call void @llvm.lifetime.start.p0(ptr 
nonnull [[DOTCOMPOUNDLITERAL]]) #[[ATTR6]]
 // SANITIZE-WITHOUT-ATTR-NEXT:    store i32 1, ptr [[DOTCOMPOUNDLITERAL]], 
align 4, !tbaa [[INT_TBAA6]]
 // SANITIZE-WITHOUT-ATTR-NEXT:    [[Y:%.*]] = getelementptr inbounds nuw i8, 
ptr [[DOTCOMPOUNDLITERAL]], i64 4
 // SANITIZE-WITHOUT-ATTR-NEXT:    store i32 2, ptr [[Y]], align 4, !tbaa 
[[INT_TBAA6]]
diff --git a/clang/test/CodeGen/attr-counted-by-without-sanitizers.c 
b/clang/test/CodeGen/attr-counted-by-without-sanitizers.c
index 7ceb51c8986bd..6efa8c9ccf5f1 100644
--- a/clang/test/CodeGen/attr-counted-by-without-sanitizers.c
+++ b/clang/test/CodeGen/attr-counted-by-without-sanitizers.c
@@ -690,6 +690,7 @@ struct compound_literal {
 // NO-SANITIZE-WITH-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr 
#[[ATTR3]] {
 // NO-SANITIZE-WITH-ATTR-NEXT:  [[ENTRY:.*:]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[DOTCOMPOUNDLITERAL:%.*]] = alloca 
[[STRUCT_COMPOUND_LITERAL:%.*]], align 4
+// NO-SANITIZE-WITH-ATTR-NEXT:    call void @llvm.lifetime.start.p0(ptr 
nonnull [[DOTCOMPOUNDLITERAL]]) #[[ATTR11]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    store i32 1, ptr [[DOTCOMPOUNDLITERAL]], 
align 4, !tbaa [[INT_TBAA6]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[Y:%.*]] = getelementptr inbounds nuw i8, 
ptr [[DOTCOMPOUNDLITERAL]], i64 4
 // NO-SANITIZE-WITH-ATTR-NEXT:    store i32 2, ptr [[Y]], align 4, !tbaa 
[[INT_TBAA6]]
@@ -697,12 +698,14 @@ struct compound_literal {
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[IDX]] to i64
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds [4 
x i8], ptr [[BLAH]], i64 [[IDXPROM]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    [[TMP0:%.*]] = load i32, ptr [[ARRAYIDX]], 
align 4, !tbaa [[INT_TBAA6]]
+// NO-SANITIZE-WITH-ATTR-NEXT:    call void @llvm.lifetime.end.p0(ptr nonnull 
[[DOTCOMPOUNDLITERAL]]) #[[ATTR11]]
 // NO-SANITIZE-WITH-ATTR-NEXT:    ret i32 [[TMP0]]
 //
 // NO-SANITIZE-WITHOUT-ATTR-LABEL: define dso_local i32 @test_compound_literal(
 // NO-SANITIZE-WITHOUT-ATTR-SAME: i32 noundef [[IDX:%.*]]) local_unnamed_addr 
#[[ATTR1]] {
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:  [[ENTRY:.*:]]
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[DOTCOMPOUNDLITERAL:%.*]] = alloca 
[[STRUCT_COMPOUND_LITERAL:%.*]], align 4
+// NO-SANITIZE-WITHOUT-ATTR-NEXT:    call void @llvm.lifetime.start.p0(ptr 
nonnull [[DOTCOMPOUNDLITERAL]]) #[[ATTR10]]
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    store i32 1, ptr [[DOTCOMPOUNDLITERAL]], 
align 4, !tbaa [[INT_TBAA6]]
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[Y:%.*]] = getelementptr inbounds nuw 
i8, ptr [[DOTCOMPOUNDLITERAL]], i64 4
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    store i32 2, ptr [[Y]], align 4, !tbaa 
[[INT_TBAA6]]
@@ -710,6 +713,7 @@ struct compound_literal {
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[IDXPROM:%.*]] = sext i32 [[IDX]] to i64
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds 
[4 x i8], ptr [[BLAH]], i64 [[IDXPROM]]
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    [[TMP0:%.*]] = load i32, ptr 
[[ARRAYIDX]], align 4, !tbaa [[INT_TBAA6]]
+// NO-SANITIZE-WITHOUT-ATTR-NEXT:    call void @llvm.lifetime.end.p0(ptr 
nonnull [[DOTCOMPOUNDLITERAL]]) #[[ATTR10]]
 // NO-SANITIZE-WITHOUT-ATTR-NEXT:    ret i32 [[TMP0]]
 //
 int test_compound_literal(int idx) {
diff --git a/clang/test/CodeGen/compound-literal-lifetime.c 
b/clang/test/CodeGen/compound-literal-lifetime.c
new file mode 100644
index 0000000000000..42186b019ef18
--- /dev/null
+++ b/clang/test/CodeGen/compound-literal-lifetime.c
@@ -0,0 +1,93 @@
+// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -O1 %s -o - | 
FileCheck %s
+
+struct foo {
+  int x;
+  int y;
+};
+
+void bar(struct foo *);
+
+// CHECK-LABEL: define dso_local void @baz()
+// CHECK: call void @llvm.lifetime.start.p0(ptr nonnull %[[SLOT1:.*]])
+// CHECK: call void @bar(ptr noundef nonnull %[[SLOT1]])
+// CHECK: call void @llvm.lifetime.end.p0(ptr nonnull %[[SLOT1]])
+// CHECK: call void @llvm.lifetime.start.p0(ptr nonnull %[[SLOT2:.*]])
+// CHECK: call void @bar(ptr noundef nonnull %[[SLOT2]])
+// CHECK: call void @llvm.lifetime.end.p0(ptr nonnull %[[SLOT2]])
+void baz(void) {
+  {
+    bar(&(struct foo){.x = 42, .y = 25});
+  }
+  {
+    bar(&(struct foo){.x = 77, .y = 99});
+  }
+}
+
+int side_effect_true(void);
+int side_effect_false(void);
+
+// Verify that initializers with side effects in conditional expressions
+// are evaluated at the point of expression evaluation (short-circuited),
+// rather than hoisted to block entry.
+// CHECK-LABEL: define dso_local void @test_conditional(
+// CHECK: cond.true:
+// CHECK: call void @llvm.lifetime.start.p0(ptr nonnull %[[CL1:.*]])
+// CHECK: call i32 @side_effect_true()
+// CHECK: cond.false:
+// CHECK: call void @llvm.lifetime.start.p0(ptr nonnull %[[CL2:.*]])
+// CHECK: call i32 @side_effect_false()
+// CHECK: cond.end:
+// CHECK: call void @bar(
+// CHECK: call void @llvm.lifetime.end.p0(ptr nonnull %[[CL2]])
+// CHECK: call void @llvm.lifetime.end.p0(ptr nonnull %[[CL1]])
+void test_conditional(int cond) {
+  cond ? bar(&(struct foo){.x = side_effect_true()})
+       : bar(&(struct foo){.x = side_effect_false()});
+}
+
+int side_effect(void);
+
+// Verify that initializers in logical short-circuiting operators are only
+// evaluated when the RHS is executed.
+// CHECK-LABEL: define dso_local void @test_short_circuit(
+// CHECK: br i1 %{{.*}}, label %{{.*}}, label %[[LAND_RHS:.*]]
+// CHECK: [[LAND_RHS]]:
+// CHECK: call i32 @side_effect()
+void test_short_circuit(int flag) {
+  if (flag && ((struct foo){.x = side_effect()}).x > 0)
+    bar(0);
+}
+
+void side_effect1(void);
+int side_effect2(void);
+void side_effect3(void);
+
+// Verify side effects are sequenced in evaluation order, not hoisted to block 
entry.
+// CHECK-LABEL: define dso_local void @test_order(
+// CHECK: call void @side_effect1()
+// CHECK: call void @llvm.lifetime.start.p0(ptr nonnull %[[CL:.*]])
+// CHECK: call i32 @side_effect2()
+// CHECK: call void @bar(ptr noundef nonnull %[[CL]])
+// CHECK: call void @side_effect3()
+// CHECK: call void @llvm.lifetime.end.p0(ptr nonnull %[[CL]])
+void test_order(void) {
+  side_effect1();
+  bar(&(struct foo){.x = side_effect2()});
+  side_effect3();
+}
+
+// Verify that lifetime markers are not emitted when a label has been seen in 
the
+// current scope, matching VarDecl behavior to avoid miscompilation on 
backward jumps.
+// CHECK-LABEL: define dso_local i32 @test_backward_goto()
+// CHECK-NOT: call void @llvm.lifetime.start
+// CHECK-NOT: call void @llvm.lifetime.end
+// CHECK: ret i32
+int test_backward_goto(void) {
+  int *p = 0;
+label:
+  if (p)
+    return *p;
+  p = &(int){10};
+  goto label;
+}
+
diff --git a/clang/test/CodeGenObjC/arc-ternary-op.m 
b/clang/test/CodeGenObjC/arc-ternary-op.m
index 46529b411f113..fe885affc2284 100644
--- a/clang/test/CodeGenObjC/arc-ternary-op.m
+++ b/clang/test/CodeGenObjC/arc-ternary-op.m
@@ -149,8 +149,10 @@ void test3(int cond) {
   // CHECK: define{{.*}} void @test3(
   // CHECK: %[[P:.*]] = alloca ptr, align 8
   // CHECK: %[[_COMPOUNDLITERAL:.*]] = alloca [2 x ptr], align 8
+  // CHECK: %[[LIFETIME_COND:.*]] = alloca i1, align 1
   // CHECK: %[[CLEANUP_COND:.*]] = alloca i1, align 1
   // CHECK: %[[_COMPOUNDLITERAL1:.*]] = alloca [2 x ptr], align 8
+  // CHECK: %[[LIFETIME_COND4:.*]] = alloca i1, align 1
   // CHECK: %[[CLEANUP_COND4:.*]] = alloca i1, align 1
 
   // CHECK: %[[V2:.*]] = load ptr, ptr @g0, align 8
diff --git a/clang/test/Sema/scope-check.c b/clang/test/Sema/scope-check.c
index f0100759ca9b2..1a9009862d8b0 100644
--- a/clang/test/Sema/scope-check.c
+++ b/clang/test/Sema/scope-check.c
@@ -264,3 +264,17 @@ void gh175549(int b, void* c) {
   (void)a[0];
 }
 
+struct TrivialCL { int a; };
+void test_trivial_compound_literal(int cond) {
+  struct TrivialCL s;
+  switch (cond) {
+  case 0:
+    s = (struct TrivialCL){ .a = 1 };
+    break;
+  case 1:
+    s = (struct TrivialCL){ .a = 2 };
+    break;
+  default:
+    break;
+  }
+}

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

Reply via email to