[cfe-commits] r161476 - in /cfe/trunk: include/clang/AST/Type.h lib/Sema/SemaExprCXX.cpp test/SemaCXX/conditional-expr.cpp test/SemaCXX/nullptr.cpp
Richard Smith
richard-llvm at metafoo.co.uk
Tue Aug 7 23:13:49 PDT 2012
Author: rsmith
Date: Wed Aug 8 01:13:49 2012
New Revision: 161476
URL: http://llvm.org/viewvc/llvm-project?rev=161476&view=rev
Log:
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.
Modified:
cfe/trunk/include/clang/AST/Type.h
cfe/trunk/lib/Sema/SemaExprCXX.cpp
cfe/trunk/test/SemaCXX/conditional-expr.cpp
cfe/trunk/test/SemaCXX/nullptr.cpp
Modified: cfe/trunk/include/clang/AST/Type.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/AST/Type.h?rev=161476&r1=161475&r2=161476&view=diff
==============================================================================
--- cfe/trunk/include/clang/AST/Type.h (original)
+++ cfe/trunk/include/clang/AST/Type.h Wed Aug 8 01:13:49 2012
@@ -378,8 +378,6 @@
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;
Modified: cfe/trunk/lib/Sema/SemaExprCXX.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Sema/SemaExprCXX.cpp?rev=161476&r1=161475&r2=161476&view=diff
==============================================================================
--- cfe/trunk/lib/Sema/SemaExprCXX.cpp (original)
+++ cfe/trunk/lib/Sema/SemaExprCXX.cpp Wed Aug 8 01:13:49 2012
@@ -4100,8 +4100,9 @@
///
/// 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 @@
// 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 @@
}
}
- // 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 @@
// 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 @@
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 @@
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 @@
}
// -- 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 @@
/// \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 @@
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();
Modified: cfe/trunk/test/SemaCXX/conditional-expr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/conditional-expr.cpp?rev=161476&r1=161475&r2=161476&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/conditional-expr.cpp (original)
+++ cfe/trunk/test/SemaCXX/conditional-expr.cpp Wed Aug 8 01:13:49 2012
@@ -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 @@
(void)(true ? (void*)0 : A()); // expected-error{{incompatible operand types}}
}
}
+
+namespace DR587 {
+ template<typename T>
+ 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'}}
+}
Modified: cfe/trunk/test/SemaCXX/nullptr.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/SemaCXX/nullptr.cpp?rev=161476&r1=161475&r2=161476&view=diff
==============================================================================
--- cfe/trunk/test/SemaCXX/nullptr.cpp (original)
+++ cfe/trunk/test/SemaCXX/nullptr.cpp Wed Aug 8 01:13:49 2012
@@ -33,8 +33,10 @@
// 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 @@
(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}}
More information about the cfe-commits
mailing list