From fa6010b6e4c6f296c5dd99f9933223f16c3c1008 Mon Sep 17 00:00:00 2001 From: Douglas Gregor Date: Wed, 19 May 2010 23:40:50 +0000 Subject: [PATCH] When a conditional operator is an rvalue of class type, we need to create a temporary copy of both the "true" and "false" results. Fixes the Boost.Interprocess failures. Daniel did all the hard work of tracking down the issue, I get to type up the trivial fix for this horrible miscompile. llvm-svn: 104184 --- clang/lib/Sema/SemaExprCXX.cpp | 27 +++++++++++++++++++++++-- clang/test/SemaCXX/conditional-expr.cpp | 20 ++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp index 0737e9f151a6..62b7b4abbc01 100644 --- a/clang/lib/Sema/SemaExprCXX.cpp +++ b/clang/lib/Sema/SemaExprCXX.cpp @@ -2265,9 +2265,32 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS, // After those conversions, one of the following shall hold: // -- The second and third operands have the same type; the result - // is of that type. - if (Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy)) + // is of that type. If the operands have class type, the result + // is a prvalue temporary of the result type, which is + // copy-initialized from either the second operand or the third + // operand depending on the value of the first operand. + if (Context.getCanonicalType(LTy) == Context.getCanonicalType(RTy)) { + if (LTy->isRecordType()) { + // The operands have class type. Make a temporary copy. + InitializedEntity Entity = InitializedEntity::InitializeTemporary(LTy); + OwningExprResult LHSCopy = PerformCopyInitialization(Entity, + SourceLocation(), + Owned(LHS)); + if (LHSCopy.isInvalid()) + return QualType(); + + OwningExprResult RHSCopy = PerformCopyInitialization(Entity, + SourceLocation(), + Owned(RHS)); + if (RHSCopy.isInvalid()) + return QualType(); + + LHS = LHSCopy.takeAs(); + RHS = RHSCopy.takeAs(); + } + return LTy; + } // Extension: conditional operator involving vector types. if (LTy->isVectorType() || RTy->isVectorType()) diff --git a/clang/test/SemaCXX/conditional-expr.cpp b/clang/test/SemaCXX/conditional-expr.cpp index f1fe8ba79bbb..a09ff2bd417d 100644 --- a/clang/test/SemaCXX/conditional-expr.cpp +++ b/clang/test/SemaCXX/conditional-expr.cpp @@ -255,3 +255,23 @@ namespace test1 { foo(a ? a->x() : 0); } } + +namespace rdar7998817 { + class X { + X(X&); // expected-note{{declared private here}} + + struct ref { }; + + public: + X(); + X(ref); + + operator ref(); + }; + + void f(bool B) { + X x; + (void)(B? x // expected-error{{calling a private constructor of class 'rdar7998817::X'}} + : X()); + } +}