Izaron created this revision. Izaron added reviewers: aaron.ballman, cor3ntin. Izaron requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
When removing nested ConstantExprs, the tree transformer doesn't remove redundant CXXFunctionalCasts that were created "above" consteval constructors. After a while it generates a call to a constructor, therefore violating the C++17 mandatory copy elision rule. Fixes https://github.com/llvm/llvm-project/issues/53244 and https://github.com/llvm/llvm-project/issues/53245 Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D119095 Files: clang/lib/Sema/SemaExpr.cpp clang/test/SemaCXX/cxx2a-consteval.cpp Index: clang/test/SemaCXX/cxx2a-consteval.cpp =================================================================== --- clang/test/SemaCXX/cxx2a-consteval.cpp +++ 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; Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -16796,6 +16796,14 @@ DRSet.erase(cast<DeclRefExpr>(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<ConstantExpr>(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) {
Index: clang/test/SemaCXX/cxx2a-consteval.cpp =================================================================== --- clang/test/SemaCXX/cxx2a-consteval.cpp +++ 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; Index: clang/lib/Sema/SemaExpr.cpp =================================================================== --- clang/lib/Sema/SemaExpr.cpp +++ clang/lib/Sema/SemaExpr.cpp @@ -16796,6 +16796,14 @@ DRSet.erase(cast<DeclRefExpr>(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<ConstantExpr>(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) {
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits