diff --git a/clang/include/clang/Sema/Scope.h b/clang/include/clang/Sema/Scope.h --- a/clang/include/clang/Sema/Scope.h +++ b/clang/include/clang/Sema/Scope.h @@ -199,6 +199,14 @@ using DeclSetTy = llvm::SmallPtrSet; DeclSetTy DeclsInScope; + /// NRVOCandidatesInScope - This keeps track of all unspoiled NRVO candidates + /// in this scope. When a VarDecl is added to the scope, it is added to + /// NRVOCandidatesInScope. When `addNRVOCandidate` is called, all variables + /// except the actual candidate are removed from the set. The set is used + /// to calculate the `NRVO` variable. + using NRVOCandidatesSetTy = llvm::SmallPtrSet; + NRVOCandidatesSetTy NRVOCandidatesInScope; + /// The DeclContext with which this scope is associated. For /// example, the entity of a class scope is the class itself, the /// entity of a function scope is a function, etc. @@ -210,7 +218,7 @@ /// Used to determine if errors occurred in this scope. DiagnosticErrorTrap ErrorTrap; - /// A lattice consisting of undefined, a single NRVO candidate variable in + /// A lattice consisting of undefined, the single NRVO candidate variable in /// this scope, or over-defined. The bit is true when over-defined. llvm::PointerIntPair NRVO; @@ -305,6 +313,8 @@ void AddDecl(Decl *D) { DeclsInScope.insert(D); + if (VarDecl *VD = dyn_cast(D)) + NRVOCandidatesInScope.insert(VD); } void RemoveDecl(Decl *D) { @@ -506,18 +516,28 @@ } void addNRVOCandidate(VarDecl *VD) { - if (NRVO.getInt()) - return; - if (NRVO.getPointer() == nullptr) { - NRVO.setPointer(VD); - return; - } - if (NRVO.getPointer() != VD) - setNoNRVO(); + // every candidate except VD is "spoiled" now, remove them from the set + bool HasCandidate = NRVOCandidatesInScope.contains(VD); + NRVOCandidatesInScope.clear(); + if (HasCandidate) + NRVOCandidatesInScope.insert(VD); + + // the variable may have NRVO if it's an existing candidate or an outer + // variable + VarDecl *NewNRVO = nullptr; + if (HasCandidate || !isDeclScope(VD)) + NewNRVO = VD; + + // if we changed the candidate, the NRVO for the parent scope is + // over-defined + if (NRVO.getPointer() != nullptr && NRVO.getPointer() != NewNRVO) + NRVO.setInt(true); + NRVO.setPointer(NewNRVO); } void setNoNRVO() { NRVO.setInt(true); + NRVOCandidatesInScope.clear(); NRVO.setPointer(nullptr); } diff --git a/clang/lib/Sema/Scope.cpp b/clang/lib/Sema/Scope.cpp --- a/clang/lib/Sema/Scope.cpp +++ b/clang/lib/Sema/Scope.cpp @@ -194,7 +194,7 @@ OS << "Entity : (clang::DeclContext*)" << DC << '\n'; if (NRVO.getInt()) - OS << "NRVO not allowed\n"; - else if (NRVO.getPointer()) + OS << "Invalidates NRVO candidates in parent\n"; + if (NRVO.getPointer()) OS << "NRVO candidate : (clang::VarDecl*)" << NRVO.getPointer() << '\n'; } diff --git a/clang/test/CodeGenCXX/nrvo.cpp b/clang/test/CodeGenCXX/nrvo.cpp --- a/clang/test/CodeGenCXX/nrvo.cpp +++ b/clang/test/CodeGenCXX/nrvo.cpp @@ -167,81 +167,13 @@ // CHECK-LABEL: @_Z5test3b( // CHECK-NEXT: entry: -// CHECK-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 -// CHECK-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] -// CHECK: if.then: // CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5]] -// CHECK-NEXT: br label [[RETURN:%.*]] -// CHECK: if.end: -// CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] -// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] -// CHECK-NEXT: br label [[RETURN]] -// CHECK: return: // CHECK-NEXT: ret void // -// CHECK-EH-03-LABEL: @_Z5test3b( -// CHECK-EH-03-NEXT: entry: -// CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 -// CHECK-EH-03-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] -// CHECK-EH-03: if.then: -// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) -// CHECK-EH-03-NEXT: br label [[RETURN:%.*]] -// CHECK-EH-03: if.end: -// CHECK-EH-03-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-03-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] -// CHECK-EH-03: invoke.cont: -// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: br label [[RETURN]] -// CHECK-EH-03: lpad: -// CHECK-EH-03-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } -// CHECK-EH-03-NEXT: cleanup -// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-03-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]] -// CHECK-EH-03: invoke.cont1: -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: resume { i8*, i32 } [[TMP1]] -// CHECK-EH-03: return: -// CHECK-EH-03-NEXT: ret void -// CHECK-EH-03: terminate.lpad: -// CHECK-EH-03-NEXT: [[TMP2:%.*]] = landingpad { i8*, i32 } -// CHECK-EH-03-NEXT: catch i8* null -// CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { i8*, i32 } [[TMP2]], 0 -// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP3]]) #[[ATTR8]] -// CHECK-EH-03-NEXT: unreachable -// -// CHECK-EH-11-LABEL: @_Z5test3b( -// CHECK-EH-11-NEXT: entry: -// CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 -// CHECK-EH-11-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] -// CHECK-EH-11: if.then: -// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) -// CHECK-EH-11-NEXT: br label [[RETURN:%.*]] -// CHECK-EH-11: if.end: -// CHECK-EH-11-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] -// CHECK-EH-11: invoke.cont: -// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: br label [[RETURN]] -// CHECK-EH-11: lpad: -// CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } -// CHECK-EH-11-NEXT: cleanup -// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: resume { i8*, i32 } [[TMP1]] -// CHECK-EH-11: return: -// CHECK-EH-11-NEXT: ret void +// CHECK-EH-LABEL: @_Z5test3b( +// CHECK-EH-NEXT: entry: +// CHECK-EH-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) +// CHECK-EH-NEXT: ret void // X test3(bool B) { // http://wg21.link/p2025r2#ex-4 if (B) { @@ -249,7 +181,7 @@ return y; // NRVO happens } X x; - return x; // FIXME: NRVO could happen, but doesn't + return x; // NRVO happens } extern "C" void exit(int) throw(); @@ -745,93 +677,24 @@ // CHECK-LABEL: @_Z6test13b( // CHECK-NEXT: entry: -// CHECK-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 -// CHECK-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] -// CHECK: if.then: // CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5]] -// CHECK-NEXT: br label [[RETURN:%.*]] -// CHECK: if.end: -// CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] -// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] -// CHECK-NEXT: br label [[RETURN]] -// CHECK: return: // CHECK-NEXT: ret void // -// CHECK-EH-03-LABEL: @_Z6test13b( -// CHECK-EH-03-NEXT: entry: -// CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 -// CHECK-EH-03-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] -// CHECK-EH-03: if.then: -// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) -// CHECK-EH-03-NEXT: br label [[RETURN:%.*]] -// CHECK-EH-03: if.end: -// CHECK-EH-03-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-03-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] -// CHECK-EH-03: invoke.cont: -// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: br label [[RETURN]] -// CHECK-EH-03: lpad: -// CHECK-EH-03-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } -// CHECK-EH-03-NEXT: cleanup -// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-03-NEXT: to label [[INVOKE_CONT1:%.*]] unwind label [[TERMINATE_LPAD:%.*]] -// CHECK-EH-03: invoke.cont1: -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: resume { i8*, i32 } [[TMP1]] -// CHECK-EH-03: return: -// CHECK-EH-03-NEXT: ret void -// CHECK-EH-03: terminate.lpad: -// CHECK-EH-03-NEXT: [[TMP2:%.*]] = landingpad { i8*, i32 } -// CHECK-EH-03-NEXT: catch i8* null -// CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { i8*, i32 } [[TMP2]], 0 -// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP3]]) #[[ATTR8]] -// CHECK-EH-03-NEXT: unreachable -// -// CHECK-EH-11-LABEL: @_Z6test13b( -// CHECK-EH-11-NEXT: entry: -// CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 -// CHECK-EH-11-NEXT: br i1 [[B:%.*]], label [[IF_THEN:%.*]], label [[IF_END:%.*]] -// CHECK-EH-11: if.then: -// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) -// CHECK-EH-11-NEXT: br label [[RETURN:%.*]] -// CHECK-EH-11: if.end: -// CHECK-EH-11-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 -// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-11-NEXT: to label [[INVOKE_CONT:%.*]] unwind label [[LPAD:%.*]] -// CHECK-EH-11: invoke.cont: -// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: br label [[RETURN]] -// CHECK-EH-11: lpad: -// CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } -// CHECK-EH-11-NEXT: cleanup -// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: resume { i8*, i32 } [[TMP1]] -// CHECK-EH-11: return: -// CHECK-EH-11-NEXT: ret void +// CHECK-EH-LABEL: @_Z6test13b( +// CHECK-EH-NEXT: entry: +// CHECK-EH-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) +// CHECK-EH-NEXT: ret void // X test13(bool b) { // http://wg21.link/p2025r2#ex-7 if (b) return X(); X x; - return x; // FIXME: NRVO could happen, but doesn't + return x; // NRVO happens } // CHECK-LABEL: @_Z6test14b( // CHECK-NEXT: entry: // CHECK-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 -// CHECK-NEXT: [[Y:%.*]] = alloca [[CLASS_X]], align 1 // CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] // CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] @@ -840,12 +703,7 @@ // CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] // CHECK-NEXT: br label [[CLEANUP:%.*]] // CHECK: if.end: -// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 -// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] -// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR5]] // CHECK-NEXT: br label [[CLEANUP]] // CHECK: cleanup: // CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] @@ -855,7 +713,6 @@ // CHECK-EH-03-LABEL: @_Z6test14b( // CHECK-EH-03-NEXT: entry: // CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 -// CHECK-EH-03-NEXT: [[Y:%.*]] = alloca [[CLASS_X]], align 1 // CHECK-EH-03-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 // CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) @@ -866,56 +723,28 @@ // CHECK-EH-03: lpad: // CHECK-EH-03-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } // CHECK-EH-03-NEXT: cleanup -// CHECK-EH-03-NEXT: br label [[EHCLEANUP7:%.*]] +// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-03-NEXT: to label [[INVOKE_CONT3:%.*]] unwind label [[TERMINATE_LPAD:%.*]] // CHECK-EH-03: if.end: -// CHECK-EH-03-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 -// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) -// CHECK-EH-03-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD1:%.*]] -// CHECK-EH-03: invoke.cont2: -// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) -// CHECK-EH-03-NEXT: to label [[INVOKE_CONT4:%.*]] unwind label [[LPAD3:%.*]] -// CHECK-EH-03: invoke.cont4: -// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) -// CHECK-EH-03-NEXT: to label [[INVOKE_CONT5:%.*]] unwind label [[LPAD1]] -// CHECK-EH-03: lpad1: -// CHECK-EH-03-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 } -// CHECK-EH-03-NEXT: cleanup -// CHECK-EH-03-NEXT: br label [[EHCLEANUP:%.*]] -// CHECK-EH-03: lpad3: -// CHECK-EH-03-NEXT: [[TMP4:%.*]] = landingpad { i8*, i32 } -// CHECK-EH-03-NEXT: cleanup -// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) -// CHECK-EH-03-NEXT: to label [[EHCLEANUP]] unwind label [[TERMINATE_LPAD:%.*]] -// CHECK-EH-03: invoke.cont5: -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: br label [[CLEANUP]] -// CHECK-EH-03: ehcleanup: -// CHECK-EH-03-NEXT: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP3]], [[LPAD1]] ], [ [[TMP4]], [[LPAD3]] ] -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: br label [[EHCLEANUP7]] +// CHECK-EH-03-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) +// CHECK-EH-03-NEXT: to label [[CLEANUP]] unwind label [[LPAD]] // CHECK-EH-03: cleanup: // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) // CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] // CHECK-EH-03-NEXT: ret void -// CHECK-EH-03: ehcleanup7: -// CHECK-EH-03-NEXT: [[DOTPN13:%.*]] = phi { i8*, i32 } [ [[TMP1]], [[LPAD]] ], [ [[DOTPN]], [[EHCLEANUP]] ] -// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-03-NEXT: to label [[INVOKE_CONT8:%.*]] unwind label [[TERMINATE_LPAD]] -// CHECK-EH-03: invoke.cont8: +// CHECK-EH-03: invoke.cont3: // CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: resume { i8*, i32 } [[DOTPN13]] +// CHECK-EH-03-NEXT: resume { i8*, i32 } [[TMP1]] // CHECK-EH-03: terminate.lpad: -// CHECK-EH-03-NEXT: [[TMP5:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: [[TMP2:%.*]] = landingpad { i8*, i32 } // CHECK-EH-03-NEXT: catch i8* null -// CHECK-EH-03-NEXT: [[TMP6:%.*]] = extractvalue { i8*, i32 } [[TMP5]], 0 -// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP6]]) #[[ATTR8]] +// CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { i8*, i32 } [[TMP2]], 0 +// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP3]]) #[[ATTR8]] // CHECK-EH-03-NEXT: unreachable // // CHECK-EH-11-LABEL: @_Z6test14b( // CHECK-EH-11-NEXT: entry: // CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 -// CHECK-EH-11-NEXT: [[Y:%.*]] = alloca [[CLASS_X]], align 1 // CHECK-EH-11-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 // CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) @@ -926,54 +755,28 @@ // CHECK-EH-11: lpad: // CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } // CHECK-EH-11-NEXT: cleanup -// CHECK-EH-11-NEXT: br label [[EHCLEANUP5:%.*]] +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: resume { i8*, i32 } [[TMP1]] // CHECK-EH-11: if.end: -// CHECK-EH-11-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 -// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) -// CHECK-EH-11-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD1:%.*]] -// CHECK-EH-11: invoke.cont2: -// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) -// CHECK-EH-11-NEXT: to label [[INVOKE_CONT4:%.*]] unwind label [[LPAD3:%.*]] -// CHECK-EH-11: invoke.cont4: -// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: br label [[CLEANUP]] -// CHECK-EH-11: lpad1: -// CHECK-EH-11-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 } -// CHECK-EH-11-NEXT: cleanup -// CHECK-EH-11-NEXT: br label [[EHCLEANUP:%.*]] -// CHECK-EH-11: lpad3: -// CHECK-EH-11-NEXT: [[TMP4:%.*]] = landingpad { i8*, i32 } -// CHECK-EH-11-NEXT: cleanup -// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: br label [[EHCLEANUP]] -// CHECK-EH-11: ehcleanup: -// CHECK-EH-11-NEXT: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP4]], [[LPAD3]] ], [ [[TMP3]], [[LPAD1]] ] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: br label [[EHCLEANUP5]] +// CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) +// CHECK-EH-11-NEXT: to label [[CLEANUP]] unwind label [[LPAD]] // CHECK-EH-11: cleanup: // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] // CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] // CHECK-EH-11-NEXT: ret void -// CHECK-EH-11: ehcleanup5: -// CHECK-EH-11-NEXT: [[DOTPN10:%.*]] = phi { i8*, i32 } [ [[TMP1]], [[LPAD]] ], [ [[DOTPN]], [[EHCLEANUP]] ] -// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: resume { i8*, i32 } [[DOTPN10]] // X test14(bool b) { // http://wg21.link/p2025r2#ex-8 X x; if (b) return x; X y; - return y; // FIXME: NRVO could happen, but doesn't + return y; // NRVO happens } // CHECK-LABEL: @_Z6test15b( // CHECK-NEXT: entry: // CHECK-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 -// CHECK-NEXT: [[Y:%.*]] = alloca [[CLASS_X]], align 1 // CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] // CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] @@ -982,12 +785,7 @@ // CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]], %class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] // CHECK-NEXT: br label [[CLEANUP:%.*]] // CHECK: if.end: -// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 -// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] -// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR5]] // CHECK-NEXT: br label [[CLEANUP]] // CHECK: cleanup: // CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR5]] @@ -997,7 +795,6 @@ // CHECK-EH-03-LABEL: @_Z6test15b( // CHECK-EH-03-NEXT: entry: // CHECK-EH-03-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 -// CHECK-EH-03-NEXT: [[Y:%.*]] = alloca [[CLASS_X]], align 1 // CHECK-EH-03-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 // CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) @@ -1008,56 +805,28 @@ // CHECK-EH-03: lpad: // CHECK-EH-03-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } // CHECK-EH-03-NEXT: cleanup -// CHECK-EH-03-NEXT: br label [[EHCLEANUP7:%.*]] +// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) +// CHECK-EH-03-NEXT: to label [[INVOKE_CONT3:%.*]] unwind label [[TERMINATE_LPAD:%.*]] // CHECK-EH-03: if.end: -// CHECK-EH-03-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 -// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) -// CHECK-EH-03-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD1:%.*]] -// CHECK-EH-03: invoke.cont2: -// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) -// CHECK-EH-03-NEXT: to label [[INVOKE_CONT4:%.*]] unwind label [[LPAD3:%.*]] -// CHECK-EH-03: invoke.cont4: -// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) -// CHECK-EH-03-NEXT: to label [[INVOKE_CONT5:%.*]] unwind label [[LPAD1]] -// CHECK-EH-03: lpad1: -// CHECK-EH-03-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 } -// CHECK-EH-03-NEXT: cleanup -// CHECK-EH-03-NEXT: br label [[EHCLEANUP:%.*]] -// CHECK-EH-03: lpad3: -// CHECK-EH-03-NEXT: [[TMP4:%.*]] = landingpad { i8*, i32 } -// CHECK-EH-03-NEXT: cleanup -// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) -// CHECK-EH-03-NEXT: to label [[EHCLEANUP]] unwind label [[TERMINATE_LPAD:%.*]] -// CHECK-EH-03: invoke.cont5: -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: br label [[CLEANUP]] -// CHECK-EH-03: ehcleanup: -// CHECK-EH-03-NEXT: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP3]], [[LPAD1]] ], [ [[TMP4]], [[LPAD3]] ] -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: br label [[EHCLEANUP7]] +// CHECK-EH-03-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) +// CHECK-EH-03-NEXT: to label [[CLEANUP]] unwind label [[LPAD]] // CHECK-EH-03: cleanup: // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) // CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] // CHECK-EH-03-NEXT: ret void -// CHECK-EH-03: ehcleanup7: -// CHECK-EH-03-NEXT: [[DOTPN13:%.*]] = phi { i8*, i32 } [ [[TMP1]], [[LPAD]] ], [ [[DOTPN]], [[EHCLEANUP]] ] -// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) -// CHECK-EH-03-NEXT: to label [[INVOKE_CONT8:%.*]] unwind label [[TERMINATE_LPAD]] -// CHECK-EH-03: invoke.cont8: +// CHECK-EH-03: invoke.cont3: // CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: resume { i8*, i32 } [[DOTPN13]] +// CHECK-EH-03-NEXT: resume { i8*, i32 } [[TMP1]] // CHECK-EH-03: terminate.lpad: -// CHECK-EH-03-NEXT: [[TMP5:%.*]] = landingpad { i8*, i32 } +// CHECK-EH-03-NEXT: [[TMP2:%.*]] = landingpad { i8*, i32 } // CHECK-EH-03-NEXT: catch i8* null -// CHECK-EH-03-NEXT: [[TMP6:%.*]] = extractvalue { i8*, i32 } [[TMP5]], 0 -// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP6]]) #[[ATTR8]] +// CHECK-EH-03-NEXT: [[TMP3:%.*]] = extractvalue { i8*, i32 } [[TMP2]], 0 +// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP3]]) #[[ATTR8]] // CHECK-EH-03-NEXT: unreachable // // CHECK-EH-11-LABEL: @_Z6test15b( // CHECK-EH-11-NEXT: entry: // CHECK-EH-11-NEXT: [[X:%.*]] = alloca [[CLASS_X:%.*]], align 1 -// CHECK-EH-11-NEXT: [[Y:%.*]] = alloca [[CLASS_X]], align 1 // CHECK-EH-11-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[X]], i32 0, i32 0 // CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) @@ -1068,48 +837,23 @@ // CHECK-EH-11: lpad: // CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } // CHECK-EH-11-NEXT: cleanup -// CHECK-EH-11-NEXT: br label [[EHCLEANUP5:%.*]] +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: resume { i8*, i32 } [[TMP1]] // CHECK-EH-11: if.end: -// CHECK-EH-11-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 -// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) -// CHECK-EH-11-NEXT: to label [[INVOKE_CONT2:%.*]] unwind label [[LPAD1:%.*]] -// CHECK-EH-11: invoke.cont2: -// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) -// CHECK-EH-11-NEXT: to label [[INVOKE_CONT4:%.*]] unwind label [[LPAD3:%.*]] -// CHECK-EH-11: invoke.cont4: -// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: br label [[CLEANUP]] -// CHECK-EH-11: lpad1: -// CHECK-EH-11-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 } -// CHECK-EH-11-NEXT: cleanup -// CHECK-EH-11-NEXT: br label [[EHCLEANUP:%.*]] -// CHECK-EH-11: lpad3: -// CHECK-EH-11-NEXT: [[TMP4:%.*]] = landingpad { i8*, i32 } -// CHECK-EH-11-NEXT: cleanup -// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: br label [[EHCLEANUP]] -// CHECK-EH-11: ehcleanup: -// CHECK-EH-11-NEXT: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP4]], [[LPAD3]] ], [ [[TMP3]], [[LPAD1]] ] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: br label [[EHCLEANUP5]] +// CHECK-EH-11-NEXT: invoke void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) +// CHECK-EH-11-NEXT: to label [[CLEANUP]] unwind label [[LPAD]] // CHECK-EH-11: cleanup: // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] // CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] // CHECK-EH-11-NEXT: ret void -// CHECK-EH-11: ehcleanup5: -// CHECK-EH-11-NEXT: [[DOTPN10:%.*]] = phi { i8*, i32 } [ [[TMP1]], [[LPAD]] ], [ [[DOTPN]], [[EHCLEANUP]] ] -// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[X]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: resume { i8*, i32 } [[DOTPN10]] // X test15(bool b) { // http://wg21.link/p2025r2#ex-15 X x; if (b) return (x); X y; - return ((y)); // FIXME: NRVO could happen, but doesn't + return ((y)); // NRVO happens } #ifdef CXX11 @@ -1337,151 +1081,54 @@ // CHECK-LABEL: @_Z6test18i( // CHECK-NEXT: entry: -// CHECK-NEXT: [[Y:%.*]] = alloca [[CLASS_X:%.*]], align 1 -// CHECK-NEXT: [[Z:%.*]] = alloca [[CLASS_X]], align 1 // CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) #[[ATTR5]] // CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 0 // CHECK-NEXT: br i1 [[CMP]], label [[RETURN:%.*]], label [[NRVO_UNUSED:%.*]] // CHECK: nrvo.unused: // CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR5]] -// CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 -// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] -// CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[I]], 1 -// CHECK-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[CLEANUP_CONT7_CRITEDGE:%.*]] -// CHECK: if.then2: -// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] -// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] -// CHECK-NEXT: br label [[RETURN]] -// CHECK: cleanup.cont7.critedge: -// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR5]] -// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR5]] -// CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Z]], i32 0, i32 0 -// CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Z]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Z]]) #[[ATTR5]] -// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Z]]) #[[ATTR5]] -// CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP1]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR5]] +// CHECK-NEXT: [[CMP2:%.*]] = icmp eq i32 [[I]], 1 +// CHECK-NEXT: br i1 [[CMP2]], label [[RETURN]], label [[NRVO_UNUSED7:%.*]] +// CHECK: nrvo.unused7: +// CHECK-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR5]] +// CHECK-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR5]] // CHECK-NEXT: br label [[RETURN]] // CHECK: return: // CHECK-NEXT: ret void // // CHECK-EH-03-LABEL: @_Z6test18i( // CHECK-EH-03-NEXT: entry: -// CHECK-EH-03-NEXT: [[Y:%.*]] = alloca [[CLASS_X:%.*]], align 1 -// CHECK-EH-03-NEXT: [[Z:%.*]] = alloca [[CLASS_X]], align 1 // CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) // CHECK-EH-03-NEXT: [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 0 // CHECK-EH-03-NEXT: br i1 [[CMP]], label [[RETURN:%.*]], label [[NRVO_UNUSED:%.*]] // CHECK-EH-03: nrvo.unused: // CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) -// CHECK-EH-03-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 -// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) -// CHECK-EH-03-NEXT: [[CMP1:%.*]] = icmp eq i32 [[I]], 1 -// CHECK-EH-03-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[CLEANUP_CONT8_CRITEDGE:%.*]] -// CHECK-EH-03: if.then2: -// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) -// CHECK-EH-03-NEXT: to label [[CLEANUP4:%.*]] unwind label [[LPAD:%.*]] -// CHECK-EH-03: lpad: -// CHECK-EH-03-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } -// CHECK-EH-03-NEXT: cleanup -// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) -// CHECK-EH-03-NEXT: to label [[INVOKE_CONT5:%.*]] unwind label [[TERMINATE_LPAD:%.*]] -// CHECK-EH-03: cleanup4: -// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: br i1 [[CMP1]], label [[RETURN]], label [[CLEANUP_CONT8:%.*]] -// CHECK-EH-03: cleanup.cont8.critedge: -// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: br label [[CLEANUP_CONT8]] -// CHECK-EH-03: cleanup.cont8: -// CHECK-EH-03-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Z]], i32 0, i32 0 -// CHECK-EH-03-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Z]]) -// CHECK-EH-03-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Z]]) -// CHECK-EH-03-NEXT: to label [[INVOKE_CONT10:%.*]] unwind label [[LPAD9:%.*]] -// CHECK-EH-03: invoke.cont10: -// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Z]]) -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) +// CHECK-EH-03-NEXT: [[CMP2:%.*]] = icmp eq i32 [[I]], 1 +// CHECK-EH-03-NEXT: br i1 [[CMP2]], label [[RETURN]], label [[NRVO_UNUSED7:%.*]] +// CHECK-EH-03: nrvo.unused7: +// CHECK-EH-03-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) +// CHECK-EH-03-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) // CHECK-EH-03-NEXT: br label [[RETURN]] -// CHECK-EH-03: invoke.cont5: -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: br label [[EH_RESUME:%.*]] -// CHECK-EH-03: lpad9: -// CHECK-EH-03-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 } -// CHECK-EH-03-NEXT: cleanup -// CHECK-EH-03-NEXT: invoke void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Z]]) -// CHECK-EH-03-NEXT: to label [[INVOKE_CONT12:%.*]] unwind label [[TERMINATE_LPAD]] -// CHECK-EH-03: invoke.cont12: -// CHECK-EH-03-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] -// CHECK-EH-03-NEXT: br label [[EH_RESUME]] // CHECK-EH-03: return: // CHECK-EH-03-NEXT: ret void -// CHECK-EH-03: eh.resume: -// CHECK-EH-03-NEXT: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP3]], [[INVOKE_CONT12]] ], [ [[TMP1]], [[INVOKE_CONT5]] ] -// CHECK-EH-03-NEXT: resume { i8*, i32 } [[DOTPN]] -// CHECK-EH-03: terminate.lpad: -// CHECK-EH-03-NEXT: [[TMP4:%.*]] = landingpad { i8*, i32 } -// CHECK-EH-03-NEXT: catch i8* null -// CHECK-EH-03-NEXT: [[TMP5:%.*]] = extractvalue { i8*, i32 } [[TMP4]], 0 -// CHECK-EH-03-NEXT: call void @__clang_call_terminate(i8* [[TMP5]]) #[[ATTR8]] -// CHECK-EH-03-NEXT: unreachable // // CHECK-EH-11-LABEL: @_Z6test18i( // CHECK-EH-11-NEXT: entry: -// CHECK-EH-11-NEXT: [[Y:%.*]] = alloca [[CLASS_X:%.*]], align 1 -// CHECK-EH-11-NEXT: [[Z:%.*]] = alloca [[CLASS_X]], align 1 // CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT:%.*]]) // CHECK-EH-11-NEXT: [[CMP:%.*]] = icmp eq i32 [[I:%.*]], 0 // CHECK-EH-11-NEXT: br i1 [[CMP]], label [[RETURN:%.*]], label [[NRVO_UNUSED:%.*]] // CHECK-EH-11: nrvo.unused: // CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Y]], i32 0, i32 0 -// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) -// CHECK-EH-11-NEXT: [[CMP1:%.*]] = icmp eq i32 [[I]], 1 -// CHECK-EH-11-NEXT: br i1 [[CMP1]], label [[IF_THEN2:%.*]], label [[CLEANUP_CONT7_CRITEDGE:%.*]] -// CHECK-EH-11: if.then2: -// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) -// CHECK-EH-11-NEXT: to label [[CLEANUP4:%.*]] unwind label [[LPAD:%.*]] -// CHECK-EH-11: lpad: -// CHECK-EH-11-NEXT: [[TMP1:%.*]] = landingpad { i8*, i32 } -// CHECK-EH-11-NEXT: cleanup -// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: br label [[EH_RESUME:%.*]] -// CHECK-EH-11: cleanup4: -// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: br i1 [[CMP1]], label [[RETURN]], label [[CLEANUP_CONT7:%.*]] -// CHECK-EH-11: cleanup.cont7.critedge: -// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Y]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP0]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: br label [[CLEANUP_CONT7]] -// CHECK-EH-11: cleanup.cont7: -// CHECK-EH-11-NEXT: [[TMP2:%.*]] = getelementptr inbounds [[CLASS_X]], %class.X* [[Z]], i32 0, i32 0 -// CHECK-EH-11-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Z]]) -// CHECK-EH-11-NEXT: invoke void @_ZN1XC1ERKS_(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]], %class.X* noundef nonnull align 1 dereferenceable(1) [[Z]]) -// CHECK-EH-11-NEXT: to label [[INVOKE_CONT9:%.*]] unwind label [[LPAD8:%.*]] -// CHECK-EH-11: invoke.cont9: -// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Z]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) +// CHECK-EH-11-NEXT: [[CMP2:%.*]] = icmp eq i32 [[I]], 1 +// CHECK-EH-11-NEXT: br i1 [[CMP2]], label [[RETURN]], label [[NRVO_UNUSED7:%.*]] +// CHECK-EH-11: nrvo.unused7: +// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) #[[ATTR7]] +// CHECK-EH-11-NEXT: call void @_ZN1XC1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[AGG_RESULT]]) // CHECK-EH-11-NEXT: br label [[RETURN]] -// CHECK-EH-11: lpad8: -// CHECK-EH-11-NEXT: [[TMP3:%.*]] = landingpad { i8*, i32 } -// CHECK-EH-11-NEXT: cleanup -// CHECK-EH-11-NEXT: call void @_ZN1XD1Ev(%class.X* noundef nonnull align 1 dereferenceable(1) [[Z]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: call void @llvm.lifetime.end.p0i8(i64 1, i8* nonnull [[TMP2]]) #[[ATTR7]] -// CHECK-EH-11-NEXT: br label [[EH_RESUME]] // CHECK-EH-11: return: // CHECK-EH-11-NEXT: ret void -// CHECK-EH-11: eh.resume: -// CHECK-EH-11-NEXT: [[DOTPN:%.*]] = phi { i8*, i32 } [ [[TMP3]], [[LPAD8]] ], [ [[TMP1]], [[LPAD]] ] -// CHECK-EH-11-NEXT: resume { i8*, i32 } [[DOTPN]] // X test18(int i) { // http://wg21.link/p2025r2#ex-11 { @@ -1492,10 +1139,10 @@ } X y; if (i == 1) - return y; // FIXME: NRVO could happen, but doesn't + return y; // NRVO happens } X z; - return z; // FIXME: NRVO could happen, but doesn't + return z; // NRVO happens } #ifdef CXX11