Author: Martin Storsjö Date: 2025-12-06T14:23:10+02:00 New Revision: 6d38c876478dac4a42f9d6e37692348deabf6a25
URL: https://github.com/llvm/llvm-project/commit/6d38c876478dac4a42f9d6e37692348deabf6a25 DIFF: https://github.com/llvm/llvm-project/commit/6d38c876478dac4a42f9d6e37692348deabf6a25.diff LOG: Revert "[clang] Limit lifetimes of temporaries to the full expression (#170517)" This reverts commit 5daad5bf45b3c7280f7b06979fb580f70e2c4fd0. That commit caused broken compilation for some cases, see https://github.com/llvm/llvm-project/pull/170517#issuecomment-3620079591. Added: Modified: clang/docs/ReleaseNotes.rst clang/include/clang/Basic/CodeGenOptions.def clang/include/clang/Options/Options.td clang/lib/CodeGen/CGCall.cpp clang/test/CodeGenCXX/stack-reuse-miscompile.cpp clang/test/CodeGenCoroutines/pr59181.cpp Removed: clang/test/CodeGen/lifetime-call-temp.c clang/test/CodeGen/lifetime-invoke-c.c clang/test/CodeGenCXX/aggregate-lifetime-invoke.cpp clang/test/CodeGenCXX/amdgcn-call-with-aggarg.cc ################################################################################ diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 8edc271b9ba0f..f31e1c343e8aa 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -86,15 +86,6 @@ Potentially Breaking Changes options-related code has been moved out of the Driver into a separate library. - The ``clangFrontend`` library no longer depends on ``clangDriver``, which may break downstream projects that relied on this transitive dependency. -- Clang is now more precise with regards to the lifetime of temporary objects - such as when aggregates are passed by value to a function, resulting in - better sharing of stack slots and reduced stack usage. This change can lead - to use-after-scope related issues in code that unintentionally relied on the - previous behavior. If recompiling with ``-fsanitize=address`` shows a - use-after-scope warning, then this is likely the case, and the report printed - should be able to help users pinpoint where the use-after-scope is occurring. - Users can use ``-Xclang -sloppy-temporary-lifetimes`` to retain the old - behavior until they are able to find and resolve issues in their code. C/C++ Language Potentially Breaking Changes ------------------------------------------- diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def index e7f5b4c9a08a9..76a6463881c6f 100644 --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -475,10 +475,6 @@ ENUM_CODEGENOPT(ZeroCallUsedRegs, ZeroCallUsedRegsKind, /// non-deleting destructors. (No effect on Microsoft ABI.) CODEGENOPT(CtorDtorReturnThis, 1, 0, Benign) -/// Set via -Xclang -sloppy-temporary-lifetimes to disable emission of lifetime -/// marker intrinsic calls. -CODEGENOPT(NoLifetimeMarkersForTemporaries, 1, 0, Benign) - /// Enables emitting Import Call sections on supported targets that can be used /// by the Windows kernel to enable import call optimization. CODEGENOPT(ImportCallOptimization, 1, 0, Benign) diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 02396fb9b4d2d..c6841937c8d39 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -8151,11 +8151,6 @@ def import_call_optimization : Flag<["-"], "import-call-optimization">, def replaceable_function: Joined<["-"], "loader-replaceable-function=">, MarshallingInfoStringVector<CodeGenOpts<"LoaderReplaceableFunctionNames">>; -def sloppy_temporary_lifetimes - : Flag<["-"], "sloppy-temporary-lifetimes">, - HelpText<"Don't emit lifetime markers for temporary objects">, - MarshallingInfoFlag<CodeGenOpts<"NoLifetimeMarkersForTemporaries">>; - } // let Visibility = [CC1Option] //===----------------------------------------------------------------------===// diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp index 84d3229863fe9..4a9025b6e0b0f 100644 --- a/clang/lib/CodeGen/CGCall.cpp +++ b/clang/lib/CodeGen/CGCall.cpp @@ -4960,27 +4960,7 @@ void CodeGenFunction::EmitCallArg(CallArgList &args, const Expr *E, return; } - AggValueSlot ArgSlot = AggValueSlot::ignored(); - // For arguments with aggregate type, create an alloca to store - // the value. If the argument's type has a destructor, that destructor - // will run at the end of the full-expression; emit matching lifetime - // markers. - // - // FIXME: For types which don't have a destructor, consider using a - // narrower lifetime bound. - if (hasAggregateEvaluationKind(E->getType())) { - RawAddress ArgSlotAlloca = Address::invalid(); - ArgSlot = CreateAggTemp(E->getType(), "agg.tmp", &ArgSlotAlloca); - - // Emit a lifetime start/end for this temporary at the end of the full - // expression. - if (!CGM.getCodeGenOpts().NoLifetimeMarkersForTemporaries && - EmitLifetimeStart(ArgSlotAlloca.getPointer())) - pushFullExprCleanup<CallLifetimeEnd>(NormalEHLifetimeMarker, - ArgSlotAlloca); - } - - args.add(EmitAnyExpr(E, ArgSlot), type); + args.add(EmitAnyExprToTemp(E), type); } QualType CodeGenFunction::getVarArgType(const Expr *Arg) { diff --git a/clang/test/CodeGen/lifetime-call-temp.c b/clang/test/CodeGen/lifetime-call-temp.c deleted file mode 100644 index 3bc68b5e8024a..0000000000000 --- a/clang/test/CodeGen/lifetime-call-temp.c +++ /dev/null @@ -1,98 +0,0 @@ -// RUN: %clang -cc1 -triple x86_64-apple-macos -O1 -disable-llvm-passes %s \ -// RUN: -emit-llvm -o - | FileCheck %s --implicit-check-not=llvm.lifetime -// RUN: %clang -cc1 -xc++ -std=c++17 -triple x86_64-apple-macos -O1 \ -// RUN: -disable-llvm-passes %s -emit-llvm -o - -Wno-return-type-c-linkage | \ -// RUN: FileCheck %s --implicit-check-not=llvm.lifetime --check-prefixes=CHECK,CXX -// RUN: %clang -cc1 -xobjective-c -triple x86_64-apple-macos -O1 \ -// RUN: -disable-llvm-passes %s -emit-llvm -o - | \ -// RUN: FileCheck %s --implicit-check-not=llvm.lifetime --check-prefixes=CHECK,OBJC -// RUN: %clang -cc1 -triple x86_64-apple-macos -O1 -disable-llvm-passes %s \ -// RUN: -emit-llvm -o - -sloppy-temporary-lifetimes | \ -// RUN: FileCheck %s --implicit-check-not=llvm.lifetime --check-prefixes=SLOPPY - -typedef struct { int x[100]; } aggregate; - -#ifdef __cplusplus -extern "C" { -#endif - -void takes_aggregate(aggregate); -aggregate gives_aggregate(); - -// CHECK-LABEL: define void @t1 -void t1() { - takes_aggregate(gives_aggregate()); - - // CHECK: [[AGGTMP:%.*]] = alloca %struct.aggregate, align 8 - // CHECK: call void @llvm.lifetime.start.p0(ptr [[AGGTMP]]) - // CHECK: call void{{.*}} @gives_aggregate(ptr{{.*}}sret(%struct.aggregate) align 4 [[AGGTMP]]) - // CHECK: call void @takes_aggregate(ptr noundef byval(%struct.aggregate) align 8 [[AGGTMP]]) - // CHECK: call void @llvm.lifetime.end.p0(ptr [[AGGTMP]]) - - // SLOPPY: [[AGGTMP:%.*]] = alloca %struct.aggregate, align 8 - // SLOPPY-NEXT: call void (ptr, ...) @gives_aggregate(ptr{{.*}}sret(%struct.aggregate) align 4 [[AGGTMP]]) - // SLOPPY-NEXT: call void @takes_aggregate(ptr noundef byval(%struct.aggregate) align 8 [[AGGTMP]]) -} - -// CHECK: declare {{.*}}llvm.lifetime.start -// CHECK: declare {{.*}}llvm.lifetime.end - -#ifdef __cplusplus -// CXX: define void @t2 -void t2() { - struct S { - S(aggregate) {} - }; - S{gives_aggregate()}; - - // CXX: [[AGG:%.*]] = alloca %struct.aggregate - // CXX: call void @llvm.lifetime.start.p0(ptr [[AGG]] - // CXX: call void @gives_aggregate(ptr{{.*}}sret(%struct.aggregate) align 4 [[AGG]]) - // CXX: call void @_ZZ2t2EN1SC1E9aggregate(ptr {{.*}}, ptr {{.*}} byval(%struct.aggregate) align 8 [[AGG]]) - // CXX: call void @llvm.lifetime.end.p0(ptr [[AGG]] -} - -struct Dtor { - ~Dtor(); -}; - -void takes_dtor(Dtor); -Dtor gives_dtor(); - -// CXX: define void @t3 -void t3() { - takes_dtor(gives_dtor()); - - // CXX: [[AGG:%.*]] = alloca %struct.Dtor - // CXX: call void @llvm.lifetime.start.p0(ptr [[AGG]]) - // CXX: call void @gives_dtor(ptr{{.*}}sret(%struct.Dtor) align 1 [[AGG]]) - // CXX: call void @takes_dtor(ptr noundef [[AGG]]) - // CXX: call void @_ZN4DtorD1Ev(ptr {{.*}} [[AGG]]) - // CXX: call void @llvm.lifetime.end.p0(ptr [[AGG]]) - // CXX: ret void -} - -#endif - -#ifdef __OBJC__ - -@interface X --m:(aggregate)x; -@end - -// OBJC: define void @t4 -void t4(X *x) { - [x m: gives_aggregate()]; - - // OBJC: [[AGG:%.*]] = alloca %struct.aggregate - // OBJC: call void @llvm.lifetime.start.p0(ptr [[AGG]] - // OBJC: call void{{.*}} @gives_aggregate(ptr{{.*}}sret(%struct.aggregate) align 4 [[AGGTMP]]) - // OBJC: call {{.*}}@objc_msgSend - // OBJC: call void @llvm.lifetime.end.p0(ptr [[AGG]] -} - -#endif - -#ifdef __cplusplus -} -#endif diff --git a/clang/test/CodeGen/lifetime-invoke-c.c b/clang/test/CodeGen/lifetime-invoke-c.c deleted file mode 100644 index f3573f4b2ec17..0000000000000 --- a/clang/test/CodeGen/lifetime-invoke-c.c +++ /dev/null @@ -1,50 +0,0 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s -O1 -disable-llvm-passes -fexceptions | FileCheck %s - -struct Trivial { - int x[100]; -}; - -void cleanup(int *p) {} -void func(struct Trivial t); -struct Trivial gen(void); - -// CHECK-LABEL: define dso_local void @test() -void test() { - int x __attribute__((cleanup(cleanup))); - - // CHECK: %[[AGG1:.*]] = alloca %struct.Trivial - // CHECK: %[[AGG2:.*]] = alloca %struct.Trivial - - // CHECK: call void @llvm.lifetime.start.p0(ptr %[[AGG1]]) - // CHECK: invoke void @gen(ptr{{.*}} sret(%struct.Trivial){{.*}} %[[AGG1]]) - - // CHECK: invoke void @func(ptr{{.*}} %[[AGG1]]) - // CHECK-NEXT: to label %[[CONT1:.*]] unwind label %[[LPAD1:.*]] - - // CHECK: [[CONT1]]: - // CHECK-NOT: call void @llvm.lifetime.end.p0(ptr %[[AGG1]]) - - // CHECK: call void @llvm.lifetime.start.p0(ptr %[[AGG2]]) - // CHECK: invoke void @gen(ptr{{.*}} sret(%struct.Trivial){{.*}} %[[AGG2]]) - // CHECK: invoke void @func(ptr{{.*}} %[[AGG2]]) - // CHECK-NEXT: to label %[[CONT2:.*]] unwind label %[[LPAD2:.*]] - - // CHECK: [[CONT2]]: - // CHECK-DAG: call void @llvm.lifetime.end.p0(ptr %[[AGG2]]) - // CHECK-DAG: call void @llvm.lifetime.end.p0(ptr %[[AGG1]]) - - // CHECK: [[LPAD1]]: - // CHECK: landingpad - // CHECK: br label %[[EHCLEANUP:.*]] - - // CHECK: [[LPAD2]]: - // CHECK: landingpad - // CHECK: call void @llvm.lifetime.end.p0(ptr %[[AGG2]]) - // CHECK: br label %[[EHCLEANUP]] - - // CHECK: [[EHCLEANUP]]: - // CHECK: call void @llvm.lifetime.end.p0(ptr %[[AGG1]]) - // CHECK: call void @cleanup - func(gen()); - func(gen()); -} diff --git a/clang/test/CodeGenCXX/aggregate-lifetime-invoke.cpp b/clang/test/CodeGenCXX/aggregate-lifetime-invoke.cpp deleted file mode 100644 index 32af6b51fe9c8..0000000000000 --- a/clang/test/CodeGenCXX/aggregate-lifetime-invoke.cpp +++ /dev/null @@ -1,47 +0,0 @@ -// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm -o - %s -O1 -fexceptions -fcxx-exceptions | FileCheck %s - -extern "C" { - -struct Trivial { - int x[100]; -}; - -void func_that_throws(Trivial t); - -// CHECK-LABEL: define{{.*}} void @test() -void test() { - // CHECK: %[[AGG1:.*]] = alloca %struct.Trivial - // CHECK: %[[AGG2:.*]] = alloca %struct.Trivial - - // CHECK: call void @llvm.lifetime.start.p0(ptr{{.*}} %[[AGG1]]) - // CHECK: invoke void @func_that_throws(ptr{{.*}} %[[AGG1]]) - // CHECK-NEXT: to label %[[CONT1:.*]] unwind label %[[LPAD1:.*]] - - // CHECK: [[CONT1]]: - // CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr{{.*}} %[[AGG2]]) - // CHECK: invoke void @func_that_throws(ptr{{.*}} %[[AGG2]]) - // CHECK-NEXT: to label %[[CONT2:.*]] unwind label %[[LPAD2:.*]] - - // CHECK: [[CONT2]]: - // CHECK-DAG: call void @llvm.lifetime.end.p0(ptr{{.*}} %[[AGG2]]) - // CHECK-DAG: call void @llvm.lifetime.end.p0(ptr{{.*}} %[[AGG1]]) - // CHECK: br label %[[TRY_CONT:.*]] - - // CHECK: [[LPAD1]]: - // CHECK: landingpad - // CHECK: br label %[[EHCLEANUP:.*]] - - // CHECK: [[LPAD2]]: - // CHECK: landingpad - // CHECK: call void @llvm.lifetime.end.p0(ptr{{.*}} %[[AGG2]]) - // CHECK: br label %[[EHCLEANUP]] - - // CHECK: [[EHCLEANUP]]: - // CHECK: call void @llvm.lifetime.end.p0(ptr{{.*}} %[[AGG1]]) - try { - func_that_throws(Trivial{0}); - func_that_throws(Trivial{0}); - } catch (...) { - } -} -} // end extern "C" diff --git a/clang/test/CodeGenCXX/amdgcn-call-with-aggarg.cc b/clang/test/CodeGenCXX/amdgcn-call-with-aggarg.cc deleted file mode 100644 index 9b598a48f6436..0000000000000 --- a/clang/test/CodeGenCXX/amdgcn-call-with-aggarg.cc +++ /dev/null @@ -1,19 +0,0 @@ -// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -emit-llvm -O3 -disable-llvm-passes -o - %s | FileCheck %s - -struct A { - float x, y, z, w; -}; - -void foo(A a); - -// CHECK-LABEL: @_Z4testv -// CHECK: [[A:%.*]] = alloca [[STRUCT_A:%.*]], align 4, addrspace(5) -// CHECK-NEXT: [[AGG_TMP:%.*]] = alloca [[STRUCT_A]], align 4, addrspace(5) -// CHECK-NEXT: [[A_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A]] to ptr -// CHECK-NEXT: [[AGG_TMP_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[AGG_TMP]] to ptr -// CHECK-NEXT: call void @llvm.lifetime.start.p5(i64 16, ptr addrspace(5) [[A]]) #[[ATTR4:[0-9]+]] -// CHECK-NEXT: call void @llvm.lifetime.start.p5(i64 16, ptr addrspace(5) [[AGG_TMP]]) #[[ATTR4]] -void test() { - A a; - foo(a); -} diff --git a/clang/test/CodeGenCXX/stack-reuse-miscompile.cpp b/clang/test/CodeGenCXX/stack-reuse-miscompile.cpp index 50c374d2710f4..67fa9f9c9cd98 100644 --- a/clang/test/CodeGenCXX/stack-reuse-miscompile.cpp +++ b/clang/test/CodeGenCXX/stack-reuse-miscompile.cpp @@ -26,8 +26,6 @@ const char * f(S s) // CHECK: [[T2:%.*]] = alloca %class.T, align 4 // CHECK: [[T3:%.*]] = alloca %class.T, align 4 // -// CHECK: [[AGG:%.*]] = alloca %class.S, align 4 -// // FIXME: We could defer starting the lifetime of the return object of concat // until the call. // CHECK: call void @llvm.lifetime.start.p0(ptr [[T1]]) @@ -36,12 +34,10 @@ const char * f(S s) // CHECK: [[T4:%.*]] = call noundef ptr @_ZN1TC1EPKc(ptr {{[^,]*}} [[T2]], ptr noundef @.str) // // CHECK: call void @llvm.lifetime.start.p0(ptr [[T3]]) -// CHECK: call void @llvm.lifetime.start.p0(ptr [[AGG]]) // CHECK: [[T5:%.*]] = call noundef ptr @_ZN1TC1E1S(ptr {{[^,]*}} [[T3]], [2 x i32] %{{.*}}) // // CHECK: call void @_ZNK1T6concatERKS_(ptr dead_on_unwind writable sret(%class.T) align 4 [[T1]], ptr {{[^,]*}} [[T2]], ptr noundef nonnull align 4 dereferenceable(16) [[T3]]) // CHECK: [[T6:%.*]] = call noundef ptr @_ZNK1T3strEv(ptr {{[^,]*}} [[T1]]) -// CHECK: call void @llvm.lifetime.end.p0(ptr [[AGG]]) // // CHECK: call void @llvm.lifetime.end.p0( // CHECK: call void @llvm.lifetime.end.p0( diff --git a/clang/test/CodeGenCoroutines/pr59181.cpp b/clang/test/CodeGenCoroutines/pr59181.cpp index a68a61984f981..21e784e0031de 100644 --- a/clang/test/CodeGenCoroutines/pr59181.cpp +++ b/clang/test/CodeGenCoroutines/pr59181.cpp @@ -49,7 +49,6 @@ void foo() { } // CHECK: cleanup.cont:{{.*}} -// CHECK-NEXT: call void @llvm.lifetime.start.p0(ptr [[AGG:%agg.tmp]]) // CHECK-NEXT: load i8 // CHECK-NEXT: trunc // CHECK-NEXT: store i1 false @@ -58,6 +57,3 @@ void foo() { // CHECK-NOT: call void @llvm.lifetime // CHECK: call void @llvm.coro.await.suspend.void( // CHECK-NEXT: %{{[0-9]+}} = call i8 @llvm.coro.suspend( - -// CHECK-LABEL: cond.end: -// check call @llvm.lifetime.end.p0(ptr [[AGG]]) _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
