[clang] 93b2629 - [clang][CodeGen] Emit lifetime markers for block-scoped compound literals in C (#219045)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Sep 11 10:53:58 PDT 2026
Author: Nick Desaulniers
Date: 2026-09-11T10:53:52-07:00
New Revision: 93b2629d1d1f52e90549e6e12901c3f51ceba273
URL: https://github.com/llvm/llvm-project/commit/93b2629d1d1f52e90549e6e12901c3f51ceba273
DIFF: https://github.com/llvm/llvm-project/commit/93b2629d1d1f52e90549e6e12901c3f51ceba273.diff
LOG: [clang][CodeGen] Emit lifetime markers for block-scoped compound literals in C (#219045)
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
Added:
clang/test/CodeGen/compound-literal-lifetime.c
Modified:
clang/lib/CodeGen/CGExpr.cpp
clang/lib/Sema/JumpDiagnostics.cpp
clang/lib/Sema/SemaExpr.cpp
clang/test/AST/ast-dump-expr-json.c
clang/test/C/C11/n1285_1.c
clang/test/CodeGen/attr-counted-by-with-sanitizers.c
clang/test/CodeGen/attr-counted-by-without-sanitizers.c
clang/test/CodeGenObjC/arc-ternary-op.m
clang/test/Sema/scope-check.c
Removed:
################################################################################
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index 1ca649afb197a..cdfedd12f5fee 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -6017,6 +6017,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 bec58da8efa00..7186aa86fae1e 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -7620,9 +7620,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 96368bb0e07b9..b6407b64988cb 100644
--- a/clang/test/CodeGen/attr-counted-by-with-sanitizers.c
+++ b/clang/test/CodeGen/attr-counted-by-with-sanitizers.c
@@ -854,6 +854,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]]
@@ -873,6 +874,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 1dd307ff7f72b..e21281304c50b 100644
--- a/clang/test/CodeGen/attr-counted-by-without-sanitizers.c
+++ b/clang/test/CodeGen/attr-counted-by-without-sanitizers.c
@@ -694,6 +694,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]]
@@ -701,12 +702,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]]
@@ -714,6 +717,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..7e996e7ac3121 100644
--- a/clang/test/Sema/scope-check.c
+++ b/clang/test/Sema/scope-check.c
@@ -264,3 +264,18 @@ void gh175549(int b, void* c) {
(void)a[0];
}
+// Ensure that we don't trigger 'jump bypasses initialization' errors for non
+// destructed types.
+void GH68746(int cond) {
+ struct TrivialCL {int a;} s;
+ switch (cond) {
+ case 0:
+ s = (struct TrivialCL){ .a = 1 };
+ break;
+ case 1:
+ s = (struct TrivialCL){ .a = 2 };
+ break;
+ default:
+ break;
+ }
+}
More information about the cfe-commits
mailing list