Author: Richard Smith Date: 2019-10-27T12:31:16-07:00 New Revision: faee39baa87e43f4b746dd77e479268391163658
URL: https://github.com/llvm/llvm-project/commit/faee39baa87e43f4b746dd77e479268391163658 DIFF: https://github.com/llvm/llvm-project/commit/faee39baa87e43f4b746dd77e479268391163658.diff LOG: PR43762: when implicitly changing the active union member for an assignment during constant evaluation, only start the lifetime of trivially-default-constructible union members. Added: Modified: clang/lib/AST/ExprConstant.cpp clang/test/SemaCXX/constant-expression-cxx2a.cpp Removed: ################################################################################ diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 42c746e60285..7ed082185670 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -5333,9 +5333,16 @@ static bool HandleUnionActiveMemberChange(EvalInfo &Info, const Expr *LHSExpr, if (!FD || FD->getType()->isReferenceType()) break; - // ... and also contains A.B if B names a union member - if (FD->getParent()->isUnion()) - UnionPathLengths.push_back({PathLength - 1, FD}); + // ... and also contains A.B if B names a union member ... + if (FD->getParent()->isUnion()) { + // ... of a non-class, non-array type, or of a class type with a + // trivial default constructor that is not deleted, or an array of + // such types. + auto *RD = + FD->getType()->getBaseElementTypeUnsafe()->getAsCXXRecordDecl(); + if (!RD || RD->hasTrivialDefaultConstructor()) + UnionPathLengths.push_back({PathLength - 1, FD}); + } E = ME->getBase(); --PathLength; diff --git a/clang/test/SemaCXX/constant-expression-cxx2a.cpp b/clang/test/SemaCXX/constant-expression-cxx2a.cpp index 7c1718cebe44..8db705dcdc67 100644 --- a/clang/test/SemaCXX/constant-expression-cxx2a.cpp +++ b/clang/test/SemaCXX/constant-expression-cxx2a.cpp @@ -584,6 +584,48 @@ namespace Union { r.b.r.b = 2; // expected-note {{read of member 'b' of union with active member 'a'}} return r.b.r.b; } + + namespace PR43762 { + struct A { int x = 1; constexpr int f() { return 1; } }; + struct B : A { int y = 1; constexpr int g() { return 2; } }; + struct C { + int x; + constexpr virtual int f() = 0; + }; + struct D : C { + int y; + constexpr virtual int f() override { return 3; } + }; + + union U { + int n; + B b; + D d; + }; + + constexpr int test(int which) { + U u{.n = 5}; + switch (which) { + case 0: + u.b.x = 10; // expected-note {{active member 'n'}} + return u.b.f(); + case 1: + u.b.y = 10; // expected-note {{active member 'n'}} + return u.b.g(); + case 2: + u.d.x = 10; // expected-note {{active member 'n'}} + return u.d.f(); + case 3: + u.d.y = 10; // expected-note {{active member 'n'}} + return u.d.f(); + } + } + + static_assert(test(0)); // expected-error {{}} expected-note {{in call}} + static_assert(test(1)); // expected-error {{}} expected-note {{in call}} + static_assert(test(2)); // expected-error {{}} expected-note {{in call}} + static_assert(test(3)); // expected-error {{}} expected-note {{in call}} + } } namespace TwosComplementShifts { _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits