diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/lib/Sema/SemaExpr.cpp @@ -15749,7 +15749,9 @@ if (hasAnyUnrecoverableErrorsInThisFunction()) DiscardCleanupsInEvaluationContext(); - assert(!Cleanup.exprNeedsCleanups() && + // Cleanups may be needed if temporaries are created in an AsmStmt. + assert((!Cleanup.exprNeedsCleanups() || + (!Compound->body_empty() && isa(Compound->body_front()))) && "cleanups within StmtExpr not correctly bound!"); PopExpressionEvaluationContext(); diff --git a/clang/test/CodeGenCXX/asm.cpp b/clang/test/CodeGenCXX/asm.cpp --- a/clang/test/CodeGenCXX/asm.cpp +++ b/clang/test/CodeGenCXX/asm.cpp @@ -1,5 +1,7 @@ // RUN: %clang_cc1 -triple i386-unknown-unknown -emit-llvm %s -o - | FileCheck %s +// CHECK: %[[STRUCT_A:.*]] = type { i8 } + struct A { ~A(); @@ -12,3 +14,18 @@ asm("" : : "r"(foo(a)) ); // rdar://8540491 // CHECK: call void @_ZN1AD1Ev } + +namespace TestTemplate { +template +void bar(A &a) { + asm("" : : "r"(foo(a)) ); +} + +// CHECK: define {{.*}}void @_ZN12TestTemplate3barIvEEvR1A( +// CHECK: %[[AGG_TMP:.*]] = alloca %[[STRUCT_A]], +// CHECK: %[[CALL:.*]] = call noundef i32 @_Z3foo1A({{.*}}%[[AGG_TMP]]) +// CHECK: call void asm sideeffect "", "r,~{dirflag},~{fpsr},~{flags}"(i32 %[[CALL]]) +// CHECK: call void @_ZN1AD1Ev({{.*}}%[[AGG_TMP]]) + +void test(A &a) { bar(a); } +} // namespace TestTemplate diff --git a/clang/test/SemaTemplate/instantiate-expr-1.cpp b/clang/test/SemaTemplate/instantiate-expr-1.cpp --- a/clang/test/SemaTemplate/instantiate-expr-1.cpp +++ b/clang/test/SemaTemplate/instantiate-expr-1.cpp @@ -190,3 +190,19 @@ test_asm_tied(1.f); // expected-note {{instantiation of}} } } + +namespace TestAsmCleanup { +struct S { + operator int() const { return 1; } + ~S(); +}; + +template +void foo() { + __asm__ __volatile__("%[i]" + : + : [i] "r"(-S())); +} + +void test() { foo(); } +} // namespace TestAsmCleanup