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; + } +} _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
