llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT--> @llvm/pr-subscribers-clang Author: Arendelle (SekaiArendelle) <details> <summary>Changes</summary> When HandleDestructionImpl destroys a class object during constant evaluation, it attempts to look up the class's destructor via getDestructor() before checking whether the record is an anonymous union. Anonymous unions should not have their destructors invoked directly during constant evaluation — their lifetime is managed by the enclosing class's destructor. Move the anonymous-union short-circuit before the getDestructor() call so anonymous unions are handled early, regardless of whether getDestructor() returns null or not. This fixes cases where an object with an implicitly-defined constexpr destructor stored inside an anonymous union member was incorrectly rejected during constant evaluation. --- Full diff: https://github.com/llvm/llvm-project/pull/197416.diff 2 Files Affected: - (modified) clang/lib/AST/ExprConstant.cpp (+9-6) - (modified) clang/test/SemaCXX/constant-expression-cxx2a.cpp (+20) ``````````diff diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 5f09c9ea4a7b8..efe9d793d2fb2 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -7370,23 +7370,26 @@ static bool HandleDestructionImpl(EvalInfo &Info, SourceRange CallRange, return false; } + // If an anonymous union would be destroyed, some enclosing destructor must + // have been explicitly defined, and the anonymous union destruction should + // have no effect. + if (RD->isAnonymousStructOrUnion() && RD->isUnion()) { + Value = APValue(); + return true; + } + const CXXDestructorDecl *DD = RD->getDestructor(); if (!DD && !RD->hasTrivialDestructor()) { Info.FFDiag(CallRange.getBegin()); return false; } - if (!DD || DD->isTrivial() || - (RD->isAnonymousStructOrUnion() && RD->isUnion())) { + if (!DD || DD->isTrivial()) { // A trivial destructor just ends the lifetime of the object. Check for // this case before checking for a body, because we might not bother // building a body for a trivial destructor. Note that it doesn't matter // whether the destructor is constexpr in this case; all trivial // destructors are constexpr. - // - // If an anonymous union would be destroyed, some enclosing destructor must - // have been explicitly defined, and the anonymous union destruction should - // have no effect. Value = APValue(); return true; } diff --git a/clang/test/SemaCXX/constant-expression-cxx2a.cpp b/clang/test/SemaCXX/constant-expression-cxx2a.cpp index 396a8df21a3e3..0748c6be0179f 100644 --- a/clang/test/SemaCXX/constant-expression-cxx2a.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx2a.cpp @@ -1518,3 +1518,23 @@ namespace GH150705 { constexpr const A& a = b; constexpr auto x = (a.*q)(); // expected-error {{constant expression}} } + +namespace GH197403 { + struct Inner { + constexpr ~Inner() noexcept {} + }; + struct Outer { + Inner inner; + }; + template<typename T> + struct BugTrigger { + union { T value; int dummy; }; + constexpr BugTrigger() : value{} {} + constexpr ~BugTrigger() noexcept { value.~T(); } + }; + consteval int test() { + BugTrigger<Outer> bt; + return 0; + } + static_assert(test() == 0); +} `````````` </details> https://github.com/llvm/llvm-project/pull/197416 _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
