From 50d61c8ccfc633b13cdf594ea3cd3a217076debe Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 8 Aug 2012 06:13:49 +0000 Subject: [PATCH] Implement final piece of DR963 and also DR587: A conditional operator between glvalues of types cv1 T and cv2 T produces a glvalue if the expressions are of the same value kind and one of cv1 and cv2 is a subset of the other. A conditional operator between two null pointer constants is permitted if one of them is of type std::nullptr_t. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@161476 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/AST/Type.h | 2 - lib/Sema/SemaExprCXX.cpp | 87 +++++++++++++++++++++---------- test/SemaCXX/conditional-expr.cpp | 26 ++++++++- test/SemaCXX/nullptr.cpp | 4 +- 4 files changed, 88 insertions(+), 31 deletions(-) diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 863a7ea4d5..00b96e6502 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -378,8 +378,6 @@ public: return hasConst(); } - bool isSupersetOf(Qualifiers Other) const; - /// \brief Determine whether this set of qualifiers is a strict superset of /// another set of qualifiers, not considering qualifier compatibility. bool isStrictSupersetOf(Qualifiers Other) const; diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 64a12a2039..37450e24c0 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -4100,8 +4100,9 @@ static bool ConvertForConditional(Sema &Self, ExprResult &E, QualType T) { /// /// See C++ [expr.cond]. Note that LHS is never null, even for the GNU x ?: y /// extension. In this case, LHS == Cond. (But they're not aliases.) -QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, ExprResult &RHS, - ExprValueKind &VK, ExprObjectKind &OK, +QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, + ExprResult &RHS, ExprValueKind &VK, + ExprObjectKind &OK, SourceLocation QuestionLoc) { // FIXME: Handle C99's complex types, vector types, block pointers and Obj-C++ // interface pointers. @@ -4177,14 +4178,10 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, Ex // Neither is void. - // C++0x 5.16p3 + // C++11 [expr.cond]p3 // Otherwise, if the second and third operand have different types, and - // either has (cv) class type, and attempt is made to convert each of those - // operands to the other. - // - // FIXME: In C++11, if both operands have the same value category and the same - // type except for cv-qualification, the types are unified. This is valid: - // volatile int a; int b; volatile int &c = x ? a : b; + // either has (cv) class type [...] an attempt is made to convert each of + // those operands to the type of the other. if (!Context.hasSameType(LTy, RTy) && (LTy->isRecordType() || RTy->isRecordType())) { ImplicitConversionSequence ICSLeftToRight, ICSRightToLeft; @@ -4217,7 +4214,31 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, Ex } } - // C++0x 5.16p4 + // C++11 [expr.cond]p3 + // if both are glvalues of the same value category and the same type except + // for cv-qualification, an attempt is made to convert each of those + // operands to the type of the other. + ExprValueKind LVK = LHS.get()->getValueKind(); + ExprValueKind RVK = RHS.get()->getValueKind(); + if (!Context.hasSameType(LTy, RTy) && + Context.hasSameUnqualifiedType(LTy, RTy) && + LVK == RVK && LVK != VK_RValue) { + // Since the unqualified types are reference-related and we require the + // result to be as if a reference bound directly, the only conversion + // we can perform is to add cv-qualifiers. + Qualifiers LCVR = Qualifiers::fromCVRMask(LTy.getCVRQualifiers()); + Qualifiers RCVR = Qualifiers::fromCVRMask(RTy.getCVRQualifiers()); + if (RCVR.isStrictSupersetOf(LCVR)) { + LHS = ImpCastExprToType(LHS.take(), RTy, CK_NoOp, LVK); + LTy = LHS.get()->getType(); + } + else if (LCVR.isStrictSupersetOf(RCVR)) { + RHS = ImpCastExprToType(RHS.take(), LTy, CK_NoOp, RVK); + RTy = RHS.get()->getType(); + } + } + + // C++11 [expr.cond]p4 // If the second and third operands are glvalues of the same value // category and have the same type, the result is of that type and // value category and it is a bit-field if the second or the third @@ -4225,9 +4246,7 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, Ex // We only extend this to bitfields, not to the crazy other kinds of // l-values. bool Same = Context.hasSameType(LTy, RTy); - if (Same && - LHS.get()->isGLValue() && - LHS.get()->getValueKind() == RHS.get()->getValueKind() && + if (Same && LVK == RVK && LVK != VK_RValue && LHS.get()->isOrdinaryOrBitFieldObject() && RHS.get()->isOrdinaryOrBitFieldObject()) { VK = LHS.get()->getValueKind(); @@ -4237,8 +4256,8 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, Ex return LTy; } - // C++0x 5.16p5 - // Otherwise, the result is an rvalue. If the second and third operands + // C++11 [expr.cond]p5 + // Otherwise, the result is a prvalue. If the second and third operands // do not have the same type, and either has (cv) class type, ... if (!Same && (LTy->isRecordType() || RTy->isRecordType())) { // ... overload resolution is used to determine the conversions (if any) @@ -4248,8 +4267,8 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, Ex return QualType(); } - // C++0x 5.16p6 - // LValue-to-rvalue, array-to-pointer, and function-to-pointer standard + // C++11 [expr.cond]p6 + // Lvalue-to-rvalue, array-to-pointer, and function-to-pointer standard // conversions are performed on the second and third operands. LHS = DefaultFunctionArrayLvalueConversion(LHS.take()); RHS = DefaultFunctionArrayLvalueConversion(RHS.take()); @@ -4302,9 +4321,11 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, Ex } // -- The second and third operands have pointer type, or one has pointer - // type and the other is a null pointer constant; pointer conversions - // and qualification conversions are performed to bring them to their - // composite pointer type. The result is of the composite pointer type. + // type and the other is a null pointer constant, or both are null + // pointer constants, at least one of which is non-integral; pointer + // conversions and qualification conversions are performed to bring them + // to their composite pointer type. The result is of the composite + // pointer type. // -- The second and third operands have pointer to member type, or one has // pointer to member type and the other is a null pointer constant; // pointer to member conversions and qualification conversions are @@ -4342,7 +4363,7 @@ QualType Sema::CXXCheckConditionalOperands(ExprResult &Cond, ExprResult &LHS, Ex /// \brief Find a merged pointer type and convert the two expressions to it. /// /// This finds the composite pointer type (or member pointer type) for @p E1 -/// and @p E2 according to C++0x 5.9p2. It converts both expressions to this +/// and @p E2 according to C++11 5.9p2. It converts both expressions to this /// type and returns it. /// It does not emit diagnostics. /// @@ -4362,15 +4383,27 @@ QualType Sema::FindCompositePointerType(SourceLocation Loc, assert(getLangOpts().CPlusPlus && "This function assumes C++"); QualType T1 = E1->getType(), T2 = E2->getType(); - if (!T1->isAnyPointerType() && !T1->isMemberPointerType() && - !T2->isAnyPointerType() && !T2->isMemberPointerType()) - return QualType(); - - // C++0x 5.9p2 + // C++11 5.9p2 // Pointer conversions and qualification conversions are performed on // pointer operands to bring them to their composite pointer type. If // one operand is a null pointer constant, the composite pointer type is - // the type of the other operand. + // std::nullptr_t if the other operand is also a null pointer constant or, + // if the other operand is a pointer, the type of the other operand. + if (!T1->isAnyPointerType() && !T1->isMemberPointerType() && + !T2->isAnyPointerType() && !T2->isMemberPointerType()) { + if (T1->isNullPtrType() && + E2->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { + E2 = ImpCastExprToType(E2, T1, CK_NullToPointer).take(); + return T1; + } + if (T2->isNullPtrType() && + E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { + E1 = ImpCastExprToType(E1, T2, CK_NullToPointer).take(); + return T2; + } + return QualType(); + } + if (E1->isNullPointerConstant(Context, Expr::NPC_ValueDependentIsNull)) { if (T2->isMemberPointerType()) E1 = ImpCastExprToType(E1, T2, CK_NullToMemberPointer).take(); diff --git a/test/SemaCXX/conditional-expr.cpp b/test/SemaCXX/conditional-expr.cpp index 4aee913277..a80eda416f 100644 --- a/test/SemaCXX/conditional-expr.cpp +++ b/test/SemaCXX/conditional-expr.cpp @@ -2,7 +2,7 @@ // C++ rules for ?: are a lot stricter than C rules, and have to take into // account more conversion options. -// This test runs in C++0x mode for the contextual conversion of the condition. +// This test runs in C++11 mode for the contextual conversion of the condition. struct ToBool { explicit operator bool(); }; @@ -328,3 +328,27 @@ namespace PR9236 { (void)(true ? (void*)0 : A()); // expected-error{{incompatible operand types}} } } + +namespace DR587 { + template + const T *f(bool b) { + static T t1 = T(); + static const T t2 = T(); + return &(b ? t1 : t2); + } + struct S {}; + template const int *f(bool); + template const S *f(bool); + + extern bool b; + int i = 0; + const int ci = 0; + volatile int vi = 0; + const volatile int cvi = 0; + + const int &cir = b ? i : ci; + volatile int &vir = b ? vi : i; + const volatile int &cvir1 = b ? ci : cvi; + const volatile int &cvir2 = b ? cvi : vi; + const volatile int &cvir3 = b ? ci : vi; // expected-error{{volatile lvalue reference to type 'const volatile int' cannot bind to a temporary of type 'int'}} +} diff --git a/test/SemaCXX/nullptr.cpp b/test/SemaCXX/nullptr.cpp index e3136039f4..d148f76698 100644 --- a/test/SemaCXX/nullptr.cpp +++ b/test/SemaCXX/nullptr.cpp @@ -33,8 +33,10 @@ nullptr_t f(nullptr_t null) // Operators (void)(null == nullptr); (void)(null <= nullptr); + (void)(null == 0); (void)(null == (void*)0); (void)((void*)0 == nullptr); + (void)(null <= 0); (void)(null <= (void*)0); (void)((void*)0 <= nullptr); (void)(0 == nullptr); @@ -44,7 +46,7 @@ nullptr_t f(nullptr_t null) (void)(1 > nullptr); // expected-error {{invalid operands to binary expression}} (void)(1 != nullptr); // expected-error {{invalid operands to binary expression}} (void)(1 + nullptr); // expected-error {{invalid operands to binary expression}} - (void)(0 ? nullptr : 0); // expected-error {{non-pointer operand type 'int' incompatible with nullptr}} + (void)(0 ? nullptr : 0); (void)(0 ? nullptr : (void*)0); (void)(0 ? nullptr : A()); // expected-error {{non-pointer operand type 'A' incompatible with nullptr}} (void)(0 ? A() : nullptr); // expected-error {{non-pointer operand type 'A' incompatible with nullptr}} -- 2.40.0