From: Sebastian Redl Date: Sun, 19 Apr 2009 21:53:20 +0000 (+0000) Subject: Conditional operator C++ checking complete. What issues remain are in more general... X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=78eb874222b7653edf7182d0d899d717d5c592c1;p=clang Conditional operator C++ checking complete. What issues remain are in more general code. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@69555 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/lib/Sema/SemaExprCXX.cpp b/lib/Sema/SemaExprCXX.cpp index 2497f509ae..d3a46dc1ac 100644 --- a/lib/Sema/SemaExprCXX.cpp +++ b/lib/Sema/SemaExprCXX.cpp @@ -1151,6 +1151,8 @@ static bool ConvertForConditional(Sema &Self, Expr *&E, ICS.Standard.ReferenceBinding) { assert(ICS.Standard.DirectBinding && "TryClassUnification should never generate indirect ref bindings"); + // FIXME: Should use CheckReferenceInit here, but we no longer have a + // reference type. Self.ImpCastExprToType(E, TargetType(ICS), true); return false; } diff --git a/lib/Sema/SemaOverload.cpp b/lib/Sema/SemaOverload.cpp index 6e2e72040e..f4b6598d9e 100644 --- a/lib/Sema/SemaOverload.cpp +++ b/lib/Sema/SemaOverload.cpp @@ -2497,6 +2497,10 @@ class BuiltinCandidateTypeSet { /// built-in candidates. TypeSet PointerTypes; + /// MemberPointerTypes - The set of member pointer types that will be + /// used in the built-in candidates. + TypeSet MemberPointerTypes; + /// EnumerationTypes - The set of enumeration types that will be /// used in the built-in candidates. TypeSet EnumerationTypes; @@ -2504,7 +2508,8 @@ class BuiltinCandidateTypeSet { /// Context - The AST context in which we will build the type sets. ASTContext &Context; - bool AddWithMoreQualifiedTypeVariants(QualType Ty); + bool AddPointerWithMoreQualifiedTypeVariants(QualType Ty); + bool AddMemberPointerWithMoreQualifiedTypeVariants(QualType Ty); public: /// iterator - Iterates through the types that are part of the set. @@ -2518,24 +2523,31 @@ public: /// pointer_begin - First pointer type found; iterator pointer_begin() { return PointerTypes.begin(); } - /// pointer_end - Last pointer type found; + /// pointer_end - Past the last pointer type found; iterator pointer_end() { return PointerTypes.end(); } + /// member_pointer_begin - First member pointer type found; + iterator member_pointer_begin() { return MemberPointerTypes.begin(); } + + /// member_pointer_end - Past the last member pointer type found; + iterator member_pointer_end() { return MemberPointerTypes.end(); } + /// enumeration_begin - First enumeration type found; iterator enumeration_begin() { return EnumerationTypes.begin(); } - /// enumeration_end - Last enumeration type found; + /// enumeration_end - Past the last enumeration type found; iterator enumeration_end() { return EnumerationTypes.end(); } }; -/// AddWithMoreQualifiedTypeVariants - Add the pointer type @p Ty to +/// AddPointerWithMoreQualifiedTypeVariants - Add the pointer type @p Ty to /// the set of pointer types along with any more-qualified variants of /// that type. For example, if @p Ty is "int const *", this routine /// will add "int const *", "int const volatile *", "int const /// restrict *", and "int const volatile restrict *" to the set of /// pointer types. Returns true if the add of @p Ty itself succeeded, /// false otherwise. -bool BuiltinCandidateTypeSet::AddWithMoreQualifiedTypeVariants(QualType Ty) { +bool +BuiltinCandidateTypeSet::AddPointerWithMoreQualifiedTypeVariants(QualType Ty) { // Insert this type. if (!PointerTypes.insert(Ty)) return false; @@ -2547,22 +2559,56 @@ bool BuiltinCandidateTypeSet::AddWithMoreQualifiedTypeVariants(QualType Ty) { // FIXME: Do we have to add CVR qualifiers at *all* levels to deal // with all pointer conversions that don't cast away constness? if (!PointeeTy.isConstQualified()) - AddWithMoreQualifiedTypeVariants + AddPointerWithMoreQualifiedTypeVariants (Context.getPointerType(PointeeTy.withConst())); if (!PointeeTy.isVolatileQualified()) - AddWithMoreQualifiedTypeVariants + AddPointerWithMoreQualifiedTypeVariants (Context.getPointerType(PointeeTy.withVolatile())); if (!PointeeTy.isRestrictQualified()) - AddWithMoreQualifiedTypeVariants + AddPointerWithMoreQualifiedTypeVariants (Context.getPointerType(PointeeTy.withRestrict())); } return true; } +/// AddMemberPointerWithMoreQualifiedTypeVariants - Add the pointer type @p Ty +/// to the set of pointer types along with any more-qualified variants of +/// that type. For example, if @p Ty is "int const *", this routine +/// will add "int const *", "int const volatile *", "int const +/// restrict *", and "int const volatile restrict *" to the set of +/// pointer types. Returns true if the add of @p Ty itself succeeded, +/// false otherwise. +bool +BuiltinCandidateTypeSet::AddMemberPointerWithMoreQualifiedTypeVariants( + QualType Ty) { + // Insert this type. + if (!MemberPointerTypes.insert(Ty)) + return false; + + if (const MemberPointerType *PointerTy = Ty->getAsMemberPointerType()) { + QualType PointeeTy = PointerTy->getPointeeType(); + const Type *ClassTy = PointerTy->getClass(); + // FIXME: Optimize this so that we don't keep trying to add the same types. + + if (!PointeeTy.isConstQualified()) + AddMemberPointerWithMoreQualifiedTypeVariants + (Context.getMemberPointerType(PointeeTy.withConst(), ClassTy)); + if (!PointeeTy.isVolatileQualified()) + AddMemberPointerWithMoreQualifiedTypeVariants + (Context.getMemberPointerType(PointeeTy.withVolatile(), ClassTy)); + if (!PointeeTy.isRestrictQualified()) + AddMemberPointerWithMoreQualifiedTypeVariants + (Context.getMemberPointerType(PointeeTy.withRestrict(), ClassTy)); + } + + return true; +} + /// AddTypesConvertedFrom - Add each of the types to which the type @p /// Ty can be implicit converted to the given set of @p Types. We're -/// primarily interested in pointer types and enumeration types. +/// primarily interested in pointer types and enumeration types. We also +/// take member pointer types, for the conditional operator. /// AllowUserConversions is true if we should look at the conversion /// functions of a class type, and AllowExplicitConversions if we /// should also include the explicit conversion functions of a class @@ -2587,14 +2633,14 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, // Insert our type, and its more-qualified variants, into the set // of types. - if (!AddWithMoreQualifiedTypeVariants(Ty)) + if (!AddPointerWithMoreQualifiedTypeVariants(Ty)) return; // Add 'cv void*' to our set of types. if (!Ty->isVoidType()) { QualType QualVoid = Context.VoidTy.getQualifiedType(PointeeTy.getCVRQualifiers()); - AddWithMoreQualifiedTypeVariants(Context.getPointerType(QualVoid)); + AddPointerWithMoreQualifiedTypeVariants(Context.getPointerType(QualVoid)); } // If this is a pointer to a class type, add pointers to its bases @@ -2612,6 +2658,10 @@ BuiltinCandidateTypeSet::AddTypesConvertedFrom(QualType Ty, AddTypesConvertedFrom(Context.getPointerType(BaseTy), false, false); } } + } else if (Ty->isMemberPointerType()) { + // Member pointers are far easier, since the pointee can't be converted. + if (!AddMemberPointerWithMoreQualifiedTypeVariants(Ty)) + return; } else if (Ty->isEnumeralType()) { EnumerationTypes.insert(Ty); } else if (AllowUserConversions) { @@ -3231,12 +3281,17 @@ Sema::AddBuiltinOperatorCandidates(OverloadedOperatorKind Op, // // T operator?(bool, T, T); // - // FIXME: pointer-to-member for (BuiltinCandidateTypeSet::iterator Ptr = CandidateTypes.pointer_begin(), E = CandidateTypes.pointer_end(); Ptr != E; ++Ptr) { QualType ParamTypes[2] = { *Ptr, *Ptr }; AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet); } + for (BuiltinCandidateTypeSet::iterator Ptr = + CandidateTypes.member_pointer_begin(), + E = CandidateTypes.member_pointer_end(); Ptr != E; ++Ptr) { + QualType ParamTypes[2] = { *Ptr, *Ptr }; + AddBuiltinCandidate(*Ptr, ParamTypes, Args, 2, CandidateSet); + } goto Conditional; } } diff --git a/test/SemaCXX/conditional-expr.cpp b/test/SemaCXX/conditional-expr.cpp index 0366e67a1b..331298dbf6 100644 --- a/test/SemaCXX/conditional-expr.cpp +++ b/test/SemaCXX/conditional-expr.cpp @@ -108,11 +108,18 @@ void test() // should fail: const lost (void)(i1 ? Base() : constder()); // expected-error {{incompatible operand types ('struct Base' and 'struct Derived const')}} (void)(i1 ? constder() : Base()); // expected-error {{incompatible operand types ('struct Derived const' and 'struct Base')}} - // FIXME: should fail: private or ambiguous base + + // FIXME: these are invalid hierarchy conversions + Priv priv; + Fin fin; (void)(i1 ? Base() : Priv()); // xpected-error private base (void)(i1 ? Priv() : Base()); // xpected-error private base (void)(i1 ? Base() : Fin()); // xpected-error ambiguous base (void)(i1 ? Fin() : Base()); // xpected-error ambiguous base + (void)(i1 ? base : priv); // xpected-error private base + (void)(i1 ? priv : base); // xpected-error private base + (void)(i1 ? base : fin); // xpected-error ambiguous base + (void)(i1 ? fin : base); // xpected-error ambiguous base // b2.2 (non-hierarchy) i1 = i1 ? I() : i1; @@ -142,9 +149,8 @@ void test() double d1 = i1 ? I() : K(); pfn = i1 ? F() : G(); DFnPtr pfm; - // FIXME: Overload resolution won't choose the member pointer yet. - //pfm = i1 ? DFnPtr() : &Base::fn1; - //pfm = i1 ? &Base::fn1 : DFnPtr(); + pfm = i1 ? DFnPtr() : &Base::fn1; + pfm = i1 ? &Base::fn1 : DFnPtr(); // p6 (final conversions) i1 = i1 ? i1 : ir1; diff --git a/www/cxx_status.html b/www/cxx_status.html index fea31b6edb..c065338eb9 100644 --- a/www/cxx_status.html +++ b/www/cxx_status.html @@ -788,9 +788,9 @@ welcome!

  5.16 [expr.cond] ✓ ✓ - + ✓ - throw expressions not supported, type unification rules are based on C only + some invalid hierarchy casts still accepted, but that's a general problem   5.17 [expr.ass]