From cde8d2fddbff55cae520d90f47f6faf124d3f953 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 3 Feb 2021 23:31:51 -0800 Subject: [PATCH] Fix miscompile when performing template instantiation of non-dependent doubly-nested implicit CXXConstructExprs. Ensure that we transform the parameter initializer using TransformInitializer rather than TransformExpr so that we properly strip down and rebuild the initialization, including any necessary CXXBindTemporaryExprs. Otherwise we can end up forgetting to destroy temporary objects used to construct a constructor parameter. --- clang/lib/Sema/TreeTransform.h | 3 ++- clang/test/CodeGenCXX/instantiate-init.cpp | 29 ++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) create mode 100644 clang/test/CodeGenCXX/instantiate-init.cpp diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 1bff267cffc8..1da28a3bb94c 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -12241,7 +12241,8 @@ TreeTransform::TransformCXXConstructExpr(CXXConstructExpr *E) { (E->getNumArgs() > 1 && getDerived().DropCallArgument(E->getArg(1)))) && (!getDerived().DropCallArgument(E->getArg(0))) && !E->isListInitialization())) - return getDerived().TransformExpr(E->getArg(0)); + return getDerived().TransformInitializer(E->getArg(0), + /*DirectInit*/ false); TemporaryBase Rebase(*this, /*FIXME*/ E->getBeginLoc(), DeclarationName()); diff --git a/clang/test/CodeGenCXX/instantiate-init.cpp b/clang/test/CodeGenCXX/instantiate-init.cpp new file mode 100644 index 000000000000..dd8a1a13bdf0 --- /dev/null +++ b/clang/test/CodeGenCXX/instantiate-init.cpp @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -std=c++14 %s -emit-llvm -o - | FileCheck %s +// RUN: %clang_cc1 -std=c++17 %s -emit-llvm -o - | FileCheck %s + +namespace std { + template class initializer_list { + const T *data; + __SIZE_TYPE__ size; + + public: + initializer_list(); + }; +} + +namespace ParenBraceInitList { + struct Vector { + Vector(std::initializer_list); + ~Vector(); + }; + + struct Base { Base(Vector) {} }; + + // CHECK: define {{.*}}18ParenBraceInitList1fILi0EE + template void f() { + // CHECK: call {{.*}}18ParenBraceInitList6VectorC1 + // CHECK: call {{.*}}18ParenBraceInitList6VectorD1 + Base({0}); + } + template void f<0>(); +}