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 @@ -16796,6 +16796,14 @@ DRSet.erase(cast(E->getCallee()->IgnoreImplicit())); return Base::TransformCXXOperatorCallExpr(E); } + /// Delete extra no-op functional casts to avoid calling a constructor + ExprResult TransformCXXFunctionalCastExpr(CXXFunctionalCastExpr *E) { + auto *CE = dyn_cast(E->getSubExpr()); + if (E->getCastKind() != CK_NoOp || !CE || !CE->isImmediateInvocation()) + return Base::TransformCXXFunctionalCastExpr(E); + RemoveImmediateInvocation(CE); + return Base::TransformExpr(CE->getSubExpr()); + } /// Base::TransformInitializer skip ConstantExpr so we need to visit them /// here. ExprResult TransformInitializer(Expr *Init, bool NotCopyInit) { diff --git a/clang/test/SemaCXX/cxx2a-consteval.cpp b/clang/test/SemaCXX/cxx2a-consteval.cpp --- a/clang/test/SemaCXX/cxx2a-consteval.cpp +++ b/clang/test/SemaCXX/cxx2a-consteval.cpp @@ -613,6 +613,45 @@ } // namespace unevaluated +namespace mandatory_copy_elision { + +struct A { + consteval A() {} + consteval A(const A &); + consteval A(A &&); + consteval void f() {} +}; + +struct B { + consteval B() {} + consteval B(const B &) = delete; + consteval B(B &&) = delete; + consteval void f() {} +}; + +struct C { + consteval C() {} + consteval void f() {} + +private: + consteval C(const C &){}; + consteval C(C &&){}; +}; + +void test() { + { A{}.f(); } + { A{A{}}.f(); } + { A{A{A{A{A{A{A{A{}}}}}}}}.f(); } + { B{}.f(); } + { B{B{}}.f(); } + { B{B{B{B{B{B{B{B{}}}}}}}}.f(); } + { C{}.f(); } + { C{C{}}.f(); } + { C{C{C{C{C{C{C{C{}}}}}}}}.f(); } +} + +} // namespace mandatory_copy_elision + namespace PR50779 { struct derp { int b = 0;