diff options
| author | Douglas Gregor <dgregor@apple.com> | 2010-08-07 11:51:51 +0000 | 
|---|---|---|
| committer | Douglas Gregor <dgregor@apple.com> | 2010-08-07 11:51:51 +0000 | 
| commit | 8b2d2fe234163745794605ef643d60f0c4875207 (patch) | |
| tree | 01f602455ca46905267e741786ccfd1c2cf2cfa8 /clang/lib | |
| parent | be051731054256489b3d8571009f059b6ae2c3b4 (diff) | |
| download | bcm5719-llvm-8b2d2fe234163745794605ef643d60f0c4875207.tar.gz bcm5719-llvm-8b2d2fe234163745794605ef643d60f0c4875207.zip  | |
Allow reference binding of a reference of Objective-C object type to
an lvalue of another, compatible Objective-C object type (e.g., a
subclass). Introduce a new initialization sequence step kind to
describe this binding, along with a new cast kind. Fixes PR7741.
llvm-svn: 110513
Diffstat (limited to 'clang/lib')
| -rw-r--r-- | clang/lib/AST/ASTContext.cpp | 6 | ||||
| -rw-r--r-- | clang/lib/AST/Expr.cpp | 2 | ||||
| -rw-r--r-- | clang/lib/Checker/GRExprEngine.cpp | 3 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CGExpr.cpp | 7 | ||||
| -rw-r--r-- | clang/lib/CodeGen/CGExprScalar.cpp | 8 | ||||
| -rw-r--r-- | clang/lib/Sema/Sema.h | 3 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaCXXCast.cpp | 3 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaInit.cpp | 49 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaInit.h | 9 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaOverload.cpp | 27 | 
10 files changed, 99 insertions, 18 deletions
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index 22e1ebf5697..2c16c073483 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -4560,6 +4560,12 @@ bool ASTContext::areComparableObjCPointerTypes(QualType LHS, QualType RHS) {           canAssignObjCInterfaces(RHSOPT, LHSOPT);  } +bool ASTContext::canBindObjCObjectType(QualType To, QualType From) { +  return canAssignObjCInterfaces( +                getObjCObjectPointerType(To)->getAs<ObjCObjectPointerType>(), +                getObjCObjectPointerType(From)->getAs<ObjCObjectPointerType>()); +} +  /// typesAreCompatible - C99 6.7.3p9: For two qualified types to be compatible,  /// both shall have the identically qualified version of a compatible type.  /// C99 6.2.7p1: Two types have compatible types if their types are the diff --git a/clang/lib/AST/Expr.cpp b/clang/lib/AST/Expr.cpp index d85162a3426..e40fc7988cb 100644 --- a/clang/lib/AST/Expr.cpp +++ b/clang/lib/AST/Expr.cpp @@ -717,6 +717,8 @@ const char *CastExpr::getCastKindName() const {      return "AnyPointerToObjCPointerCast";    case CastExpr::CK_AnyPointerToBlockPointerCast:      return "AnyPointerToBlockPointerCast"; +  case CastExpr::CK_ObjCObjectLValueCast: +    return "ObjCObjectLValueCast";    }    assert(0 && "Unhandled cast kind!"); diff --git a/clang/lib/Checker/GRExprEngine.cpp b/clang/lib/Checker/GRExprEngine.cpp index ccb836fb695..4c1838f596d 100644 --- a/clang/lib/Checker/GRExprEngine.cpp +++ b/clang/lib/Checker/GRExprEngine.cpp @@ -2514,7 +2514,8 @@ void GRExprEngine::VisitCast(const CastExpr *CastE, const Expr *Ex,    case CastExpr::CK_AnyPointerToObjCPointerCast:    case CastExpr::CK_AnyPointerToBlockPointerCast:    case CastExpr::CK_DerivedToBase: -  case CastExpr::CK_UncheckedDerivedToBase: { +  case CastExpr::CK_UncheckedDerivedToBase: +  case CastExpr::CK_ObjCObjectLValueCast: {      // Delegate to SValuator to process.      for (ExplodedNodeSet::iterator I = S2.begin(), E = S2.end(); I != E; ++I) {        ExplodedNode* N = *I; diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp index 9424776898b..e2ccf55f937 100644 --- a/clang/lib/CodeGen/CGExpr.cpp +++ b/clang/lib/CodeGen/CGExpr.cpp @@ -1851,6 +1851,13 @@ LValue CodeGenFunction::EmitCastLValue(const CastExpr *E) {                                             ConvertType(CE->getTypeAsWritten()));      return LValue::MakeAddr(V, MakeQualifiers(E->getType()));    } +  case CastExpr::CK_ObjCObjectLValueCast: { +    LValue LV = EmitLValue(E->getSubExpr()); +    QualType ToType = getContext().getLValueReferenceType(E->getType()); +    llvm::Value *V = Builder.CreateBitCast(LV.getAddress(),  +                                           ConvertType(ToType)); +    return LValue::MakeAddr(V, MakeQualifiers(E->getType())); +  }    }    llvm_unreachable("Unhandled lvalue cast kind?"); diff --git a/clang/lib/CodeGen/CGExprScalar.cpp b/clang/lib/CodeGen/CGExprScalar.cpp index dbafd2bffe8..c9e4dbd1405 100644 --- a/clang/lib/CodeGen/CGExprScalar.cpp +++ b/clang/lib/CodeGen/CGExprScalar.cpp @@ -925,7 +925,8 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {      //assert(0 && "Unknown cast kind!");      break; -  case CastExpr::CK_LValueBitCast: { +  case CastExpr::CK_LValueBitCast:  +  case CastExpr::CK_ObjCObjectLValueCast: {      Value *V = EmitLValue(E).getAddress();      V = Builder.CreateBitCast(V,                             ConvertType(CGF.getContext().getPointerType(DestTy))); @@ -1044,7 +1045,10 @@ Value *ScalarExprEmitter::EmitCastExpr(CastExpr *CE) {      return Builder.CreatePtrToInt(Src, ConvertType(DestTy));    }    case CastExpr::CK_ToVoid: { -    CGF.EmitAnyExpr(E, 0, false, true); +    if (E->Classify(CGF.getContext()).isGLValue()) +      CGF.EmitLValue(E); +    else +      CGF.EmitAnyExpr(E, 0, false, true);      return 0;    }    case CastExpr::CK_VectorSplat: { diff --git a/clang/lib/Sema/Sema.h b/clang/lib/Sema/Sema.h index 3570a774b36..d22714adedd 100644 --- a/clang/lib/Sema/Sema.h +++ b/clang/lib/Sema/Sema.h @@ -4517,7 +4517,8 @@ public:    ReferenceCompareResult CompareReferenceRelationship(SourceLocation Loc,                                                        QualType T1, QualType T2, -                                                      bool& DerivedToBase); +                                                      bool &DerivedToBase, +                                                      bool &ObjCConversion);    /// CheckCastTypes - Check type constraints for casting between types under    /// C semantics, or forward to CXXCheckCStyleCast in C++. diff --git a/clang/lib/Sema/SemaCXXCast.cpp b/clang/lib/Sema/SemaCXXCast.cpp index 53352661da5..4ee20a119c9 100644 --- a/clang/lib/Sema/SemaCXXCast.cpp +++ b/clang/lib/Sema/SemaCXXCast.cpp @@ -646,9 +646,10 @@ TryLValueToRValueCast(Sema &Self, Expr *SrcExpr, QualType DestType,    // this is the only cast possibility, so we issue an error if we fail now.    // FIXME: Should allow casting away constness if CStyle.    bool DerivedToBase; +  bool ObjCConversion;    if (Self.CompareReferenceRelationship(SrcExpr->getLocStart(),                                          SrcExpr->getType(), R->getPointeeType(), -                                        DerivedToBase) < +                                        DerivedToBase, ObjCConversion) <          Sema::Ref_Compatible_With_Added_Qualification) {      msg = diag::err_bad_lvalue_to_rvalue_cast;      return TC_Failed; diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 5ffb6481206..98a3a03bb26 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -2035,6 +2035,7 @@ void InitializationSequence::Step::Destroy() {    case SK_ZeroInitialization:    case SK_CAssignment:    case SK_StringInit: +  case SK_ObjCObjectConversion:      break;    case SK_ConversionSequence: @@ -2201,6 +2202,13 @@ void InitializationSequence::AddStringInitStep(QualType T) {    Steps.push_back(S);  } +void InitializationSequence::AddObjCObjectConversionStep(QualType T) { +  Step S; +  S.Kind = SK_ObjCObjectConversion; +  S.Type = T; +  Steps.push_back(S); +} +  void InitializationSequence::SetOverloadFailure(FailureKind Failure,                                                   OverloadingResult Result) {    SequenceKind = FailedSequence; @@ -2275,10 +2283,13 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,    QualType T2 = cv2T2.getUnqualifiedType();    bool DerivedToBase; +  bool ObjCConversion;    assert(!S.CompareReferenceRelationship(Initializer->getLocStart(),  -                                         T1, T2, DerivedToBase) && +                                         T1, T2, DerivedToBase, +                                         ObjCConversion) &&           "Must have incompatible references when binding via conversion");    (void)DerivedToBase; +  (void)ObjCConversion;    // Build the candidate set directly in the initialization sequence    // structure, so that it will persist if we fail. @@ -2400,10 +2411,11 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,          ImplicitCastExpr::LValue : ImplicitCastExpr::XValue;    bool NewDerivedToBase = false; +  bool NewObjCConversion = false;    Sema::ReferenceCompareResult NewRefRelationship      = S.CompareReferenceRelationship(DeclLoc, T1,                                        T2.getNonLValueExprType(S.Context), -                                     NewDerivedToBase); +                                     NewDerivedToBase, NewObjCConversion);    if (NewRefRelationship == Sema::Ref_Incompatible) {      // If the type we've converted to is not reference-related to the      // type we're looking for, then there is another conversion step @@ -2418,8 +2430,12 @@ static OverloadingResult TryRefInitWithConversionFunction(Sema &S,      Sequence.AddDerivedToBaseCastStep(                                  S.Context.getQualifiedType(T1,                                    T2.getNonReferenceType().getQualifiers()),  -                                  Category); -   +                                      Category); +  else if (NewObjCConversion) +    Sequence.AddObjCObjectConversionStep( +                                S.Context.getQualifiedType(T1, +                                  T2.getNonReferenceType().getQualifiers())); +    if (cv1T1.getQualifiers() != T2.getNonReferenceType().getQualifiers())      Sequence.AddQualificationConversionStep(cv1T1, Category); @@ -2467,9 +2483,11 @@ static void TryReferenceInitialization(Sema &S,    bool isLValueRef = DestType->isLValueReferenceType();    bool isRValueRef = !isLValueRef;    bool DerivedToBase = false; +  bool ObjCConversion = false;    Expr::Classification InitCategory = Initializer->Classify(S.Context);    Sema::ReferenceCompareResult RefRelationship -    = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, DerivedToBase); +    = S.CompareReferenceRelationship(DeclLoc, cv1T1, cv2T2, DerivedToBase, +                                     ObjCConversion);    // C++0x [dcl.init.ref]p5:    //   A reference to type "cv1 T1" is initialized by an expression of type  @@ -2497,6 +2515,10 @@ static void TryReferenceInitialization(Sema &S,          Sequence.AddDerivedToBaseCastStep(                           S.Context.getQualifiedType(T1, T2Quals),                            ImplicitCastExpr::LValue); +      else if (ObjCConversion) +        Sequence.AddObjCObjectConversionStep( +                                     S.Context.getQualifiedType(T1, T2Quals)); +        if (T1Quals != T2Quals)          Sequence.AddQualificationConversionStep(cv1T1,ImplicitCastExpr::LValue);        bool BindingTemporary = T1Quals.hasConst() && !T1Quals.hasVolatile() && @@ -2577,6 +2599,10 @@ static void TryReferenceInitialization(Sema &S,                           S.Context.getQualifiedType(T1, T2Quals),                            isXValue ? ImplicitCastExpr::XValue                                    : ImplicitCastExpr::RValue); +      else if (ObjCConversion) +        Sequence.AddObjCObjectConversionStep( +                                     S.Context.getQualifiedType(T1, T2Quals)); +        if (T1Quals != T2Quals)          Sequence.AddQualificationConversionStep(cv1T1,                       isXValue ? ImplicitCastExpr::XValue @@ -3546,6 +3572,7 @@ InitializationSequence::Perform(Sema &S,    case SK_ListInitialization:    case SK_CAssignment:    case SK_StringInit: +  case SK_ObjCObjectConversion:      assert(Args.size() == 1);      CurInit = Sema::OwningExprResult(S, ((Expr **)(Args.get()))[0]->Retain());      if (CurInit.isInvalid()) @@ -3926,6 +3953,14 @@ InitializationSequence::Perform(Sema &S,        CheckStringInit(CurInitExpr, ResultType ? *ResultType : Ty, S);        break;      } + +    case SK_ObjCObjectConversion: +      S.ImpCastExprToType(CurInitExpr, Step->Type,  +                          CastExpr::CK_ObjCObjectLValueCast, +                          S.CastCategory(CurInitExpr)); +      CurInit.release(); +      CurInit = S.Owned(CurInitExpr); +      break;      }    } @@ -4392,6 +4427,10 @@ void InitializationSequence::dump(llvm::raw_ostream &OS) const {      case SK_StringInit:        OS << "string initialization";        break; + +    case SK_ObjCObjectConversion: +      OS << "Objective-C object conversion"; +      break;      }    }  } diff --git a/clang/lib/Sema/SemaInit.h b/clang/lib/Sema/SemaInit.h index 52481bb2564..db0b7c3bd11 100644 --- a/clang/lib/Sema/SemaInit.h +++ b/clang/lib/Sema/SemaInit.h @@ -479,7 +479,10 @@ public:      /// \brief C assignment      SK_CAssignment,      /// \brief Initialization by string -    SK_StringInit +    SK_StringInit, +    /// \brief An initialization that "converts" an Objective-C object +    /// (not a point to an object) to another Objective-C object type. +    SK_ObjCObjectConversion    };    /// \brief A single step in the initialization sequence. @@ -737,6 +740,10 @@ public:    /// \brief Add a string init step.    void AddStringInitStep(QualType T); +  /// \brief Add an Objective-C object conversion step, which is +  /// always a no-op. +  void AddObjCObjectConversionStep(QualType T); +    /// \brief Note that this initialization sequence failed.    void SetFailed(FailureKind Failure) {      SequenceKind = FailedSequence; diff --git a/clang/lib/Sema/SemaOverload.cpp b/clang/lib/Sema/SemaOverload.cpp index 27e6c2c2a34..d3855a52a13 100644 --- a/clang/lib/Sema/SemaOverload.cpp +++ b/clang/lib/Sema/SemaOverload.cpp @@ -2575,7 +2575,8 @@ Sema::CompareDerivedToBaseConversions(const StandardConversionSequence& SCS1,  Sema::ReferenceCompareResult  Sema::CompareReferenceRelationship(SourceLocation Loc,                                     QualType OrigT1, QualType OrigT2, -                                   bool& DerivedToBase) { +                                   bool &DerivedToBase, +                                   bool &ObjCConversion) {    assert(!OrigT1->isReferenceType() &&      "T1 must be the pointee type of the reference type");    assert(!OrigT2->isReferenceType() && "T2 cannot be a reference type"); @@ -2590,11 +2591,17 @@ Sema::CompareReferenceRelationship(SourceLocation Loc,    //   Given types "cv1 T1" and "cv2 T2," "cv1 T1" is    //   reference-related to "cv2 T2" if T1 is the same type as T2, or    //   T1 is a base class of T2. -  if (UnqualT1 == UnqualT2) -    DerivedToBase = false; -  else if (!RequireCompleteType(Loc, OrigT2, PDiag()) && +  DerivedToBase = false; +  ObjCConversion = false; +  if (UnqualT1 == UnqualT2) { +    // Nothing to do. +  } else if (!RequireCompleteType(Loc, OrigT2, PDiag()) &&             IsDerivedFrom(UnqualT2, UnqualT1))      DerivedToBase = true; +  else if (UnqualT1->isObjCObjectOrInterfaceType() && +           UnqualT2->isObjCObjectOrInterfaceType() && +           Context.canBindObjCObjectType(UnqualT1, UnqualT2)) +    ObjCConversion = true;    else      return Ref_Incompatible; @@ -2741,9 +2748,11 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,    // Compute some basic properties of the types and the initializer.    bool isRValRef = DeclType->isRValueReferenceType();    bool DerivedToBase = false; +  bool ObjCConversion = false;    Expr::Classification InitCategory = Init->Classify(S.Context);    Sema::ReferenceCompareResult RefRelationship -    = S.CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase); +    = S.CompareReferenceRelationship(DeclLoc, T1, T2, DerivedToBase, +                                     ObjCConversion);    // C++0x [dcl.init.ref]p5: @@ -2769,7 +2778,9 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,        //   derived-to-base Conversion (13.3.3.1).        ICS.setStandard();        ICS.Standard.First = ICK_Identity; -      ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity; +      ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base +                         : ObjCConversion? ICK_Compatible_Conversion +                         : ICK_Identity;        ICS.Standard.Third = ICK_Identity;        ICS.Standard.FromTypePtr = T2.getAsOpaquePtr();        ICS.Standard.setToType(0, T2); @@ -2857,7 +2868,9 @@ TryReferenceInit(Sema &S, Expr *&Init, QualType DeclType,        RefRelationship >= Sema::Ref_Compatible_With_Added_Qualification) {      ICS.setStandard();      ICS.Standard.First = ICK_Identity; -    ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base : ICK_Identity; +    ICS.Standard.Second = DerivedToBase? ICK_Derived_To_Base  +                        : ObjCConversion? ICK_Compatible_Conversion +                        : ICK_Identity;      ICS.Standard.Third = ICK_Identity;      ICS.Standard.FromTypePtr = T2.getAsOpaquePtr();      ICS.Standard.setToType(0, T2);  | 

