Another piece of the conditional operator puzzle. We'll want to use FindCompositePointerType in some other places, too.

llvm-svn: 69534
This commit is contained in:
Sebastian Redl 2009-04-19 19:26:31 +00:00
parent 1377dc4c79
commit 3b7ef5e374
3 changed files with 99 additions and 18 deletions

View File

@ -2389,7 +2389,7 @@ public:
QualType rhsType);
// Helper function for CheckAssignmentConstraints involving two
// blcok pointer types.
// block pointer types.
AssignConvertType CheckBlockPointerTypesForAssignment(QualType lhsType,
QualType rhsType);
@ -2440,6 +2440,7 @@ public:
Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc);
QualType CXXCheckConditionalOperands( // C++ 5.16
Expr *&cond, Expr *&lhs, Expr *&rhs, SourceLocation questionLoc);
QualType FindCompositePointerType(Expr *&E1, Expr *&E2); // C++ 5.9
/// type checking for vector binary operators.
inline QualType CheckVectorOperands(SourceLocation l, Expr *&lex, Expr *&rex);

View File

@ -1307,21 +1307,101 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
// 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.
// Fourth bullet is same for pointers-to-member.
if ((LTy->isPointerType() || LTy->isMemberPointerType()) &&
RHS->isNullPointerConstant(Context)) {
ImpCastExprToType(RHS, LTy); // promote the null to a pointer.
return LTy;
}
if ((RTy->isPointerType() || RTy->isMemberPointerType()) &&
LHS->isNullPointerConstant(Context)) {
ImpCastExprToType(LHS, RTy); // promote the null to a pointer.
return RTy;
}
QualType Composite = FindCompositePointerType(LHS, RHS);
if (!Composite.isNull())
return Composite;
// FIXME: Handle the case where both are pointers.
// Fourth bullet is same for pointers-to-member.
// FIXME: Handle this case where both are member pointers.
Diag(QuestionLoc, diag::err_typecheck_cond_incompatible_operands)
<< LHS->getType() << RHS->getType()
<< LHS->getSourceRange() << RHS->getSourceRange();
return QualType();
}
/// \brief Find a merged pointer type and convert the two expressions to it.
///
/// This finds the composite pointer type for @p E1 and @p E2 according to
/// C++0x 5.9p2. It converts both expressions to this type and returns it.
/// It does not emit diagnostics.
QualType Sema::FindCompositePointerType(Expr *&E1, Expr *&E2) {
assert(getLangOptions().CPlusPlus && "This function assumes C++");
QualType T1 = E1->getType(), T2 = E2->getType();
if(!T1->isPointerType() && !T2->isPointerType())
return QualType();
// C++0x 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.
if (E1->isNullPointerConstant(Context)) {
ImpCastExprToType(E1, T2);
return T2;
}
if (E2->isNullPointerConstant(Context)) {
ImpCastExprToType(E2, T1);
return T1;
}
// Now both have to be pointers.
if(!T1->isPointerType() || !T2->isPointerType())
return QualType();
// Otherwise, of one of the operands has type "pointer to cv1 void," then
// the other has type "pointer to cv2 T" and the composite pointer type is
// "pointer to cv12 void," where cv12 is the union of cv1 and cv2.
// Otherwise, the composite pointer type is a pointer type similar to the
// type of one of the operands, with a cv-qualification signature that is
// the union of the cv-qualification signatures of the operand types.
// In practice, the first part here is redundant; it's subsumed by the second.
// What we do here is, we build the two possible composite types, and try the
// conversions in both directions. If only one works, or if the two composite
// types are the same, we have succeeded.
llvm::SmallVector<unsigned, 4> QualifierUnion;
QualType Composite1 = T1, Composite2 = T2;
const PointerType *Ptr1, *Ptr2;
while ((Ptr1 = Composite1->getAsPointerType()) &&
(Ptr2 = Composite2->getAsPointerType())) {
Composite1 = Ptr1->getPointeeType();
Composite2 = Ptr2->getPointeeType();
QualifierUnion.push_back(
Composite1.getCVRQualifiers() | Composite2.getCVRQualifiers());
}
// Rewrap the composites as pointers with the union CVRs.
for (llvm::SmallVector<unsigned, 4>::iterator I = QualifierUnion.begin(),
E = QualifierUnion.end(); I != E; ++I) {
Composite1 = Context.getPointerType(Composite1.getQualifiedType(*I));
Composite2 = Context.getPointerType(Composite2.getQualifiedType(*I));
}
ImplicitConversionSequence E1ToC1 = TryImplicitConversion(E1, Composite1);
ImplicitConversionSequence E2ToC1 = TryImplicitConversion(E2, Composite1);
ImplicitConversionSequence E1ToC2, E2ToC2;
E1ToC2.ConversionKind = ImplicitConversionSequence::BadConversion;
E2ToC2.ConversionKind = ImplicitConversionSequence::BadConversion;
if (Context.getCanonicalType(Composite1) !=
Context.getCanonicalType(Composite2)) {
E1ToC2 = TryImplicitConversion(E1, Composite2);
E2ToC2 = TryImplicitConversion(E2, Composite2);
}
bool ToC1Viable = E1ToC1.ConversionKind !=
ImplicitConversionSequence::BadConversion
&& E2ToC1.ConversionKind !=
ImplicitConversionSequence::BadConversion;
bool ToC2Viable = E1ToC2.ConversionKind !=
ImplicitConversionSequence::BadConversion
&& E2ToC2.ConversionKind !=
ImplicitConversionSequence::BadConversion;
if (ToC1Viable && !ToC2Viable) {
if (!PerformImplicitConversion(E1, Composite1, E1ToC1, "converting") &&
!PerformImplicitConversion(E2, Composite1, E2ToC1, "converting"))
return Composite1;
}
if (ToC2Viable && !ToC1Viable) {
if (!PerformImplicitConversion(E1, Composite2, E1ToC2, "converting") &&
!PerformImplicitConversion(E2, Composite2, E2ToC2, "converting"))
return Composite2;
}
return QualType();
}

View File

@ -146,13 +146,13 @@ void test()
i1 = i1 ? EVal : i1;
d1 = i1 ? 'c' : 4.0;
d1 = i1 ? 4.0 : 'c';
pfm = i1 ? &Derived::fn2 : 0;
pfm = i1 ? 0 : &Derived::fn2;
// FIXME: pointer conversions don't work yet.
//Base *pb = i1 ? (Base*)0 : (Derived*)0;
//Base *pb = i1 ? (Derived*)0 : (Base*)0;
Base *pb = i1 ? (Base*)0 : (Derived*)0;
pb = i1 ? (Derived*)0 : (Base*)0;
// FIXME: member pointer conversions don't work yet.
//pfm = i1 ? &Base::fn1 : &Derived::fn2;
//pfm = i1 ? &Derived::fn2 : &Base::fn1;
//pfm = i1 ? &Derived::fn2 : 0;
//pfm = i1 ? 0 : &Derived::fn2;
// Conversion of primitives does not result in an lvalue.
&(i1 ? i1 : d1); // expected-error {{address expression must be an lvalue or a function designator}}