Anastasia created this revision.
Anastasia added a reviewer: rjmccall.
Herald added a subscriber: ebevhan.
Anastasia edited the summary of this revision.

Currently in C++ we don't set/propagate what type of implicit conversions 
occurs on assignments/initializations/params/etc. Therefore the diagnostic 
provided is more generic than in C mode. This patch attempt to propagate the 
conversion kind through layers of C++ semantic checks. It is currently only 
used for address spaces conversion of nested pointers (from 
https://reviews.llvm.org/D73360). Setting this for other conversions would be 
quite a lot of work and I am not sure I feel confident to get it right. We 
could potentially gradually modify it as we go along. Although this is not an 
actively modified code base at the moment so not sure whether it will happen 
and when.

Feedback welcome!


https://reviews.llvm.org/D74116

Files:
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaExceptionSpec.cpp
  clang/lib/Sema/SemaExpr.cpp
  clang/lib/Sema/SemaExprCXX.cpp
  clang/lib/Sema/SemaInit.cpp
  clang/lib/Sema/SemaOverload.cpp
  clang/lib/Sema/SemaTemplate.cpp
  clang/lib/Sema/SemaTemplateDeduction.cpp
  clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl

Index: clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl
===================================================================
--- clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl
+++ clang/test/SemaOpenCL/address-spaces-conversions-cl2.0.cl
@@ -515,11 +515,7 @@
   // Case 3: Corresponded inner pointees has overlapping but not equivalent address spaces.
   var_as_as_int = var_asc_asc_int;
 #ifdef GENERIC
-#if !__OPENCL_CPP_VERSION__
-// expected-error@-3 {{assigning '__local int *__local *__private' to '__generic int *__generic *__private' changes address space of nested pointer}}
-#else
-// expected-error@-5 {{assigning to '__generic int *__generic *' from incompatible type '__local int *__local *__private'}}
-#endif
+// expected-error-re@-2{{assigning '__local int *__local *__private' to '__generic int *__generic {{\*|\*__private}}' changes address space of nested pointer}}
 #endif
 
   var_as_as_int = (AS int *AS *)var_asc_asc_int;
Index: clang/lib/Sema/SemaTemplateDeduction.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateDeduction.cpp
+++ clang/lib/Sema/SemaTemplateDeduction.cpp
@@ -3286,9 +3286,10 @@
   // function types (recursively).
   bool ObjCLifetimeConversion = false;
   QualType ResultTy;
+  Sema::AssignConvertType ConvType = Sema::Compatible;
   if ((A->isAnyPointerType() || A->isMemberPointerType()) &&
       (S.IsQualificationConversion(A, DeducedA, false,
-                                   ObjCLifetimeConversion) ||
+                                   ObjCLifetimeConversion, ConvType) ||
        S.IsFunctionConversion(A, DeducedA, ResultTy)))
     return Sema::TDK_Success;
 
Index: clang/lib/Sema/SemaTemplate.cpp
===================================================================
--- clang/lib/Sema/SemaTemplate.cpp
+++ clang/lib/Sema/SemaTemplate.cpp
@@ -5847,9 +5847,10 @@
        !EvalResult.Val.getMemberPointerDecl())) {
     // If our expression has an appropriate type, we've succeeded.
     bool ObjCLifetimeConversion;
+    Sema::AssignConvertType ConvType = Sema::Compatible;
     if (S.Context.hasSameUnqualifiedType(Arg->getType(), ParamType) ||
         S.IsQualificationConversion(Arg->getType(), ParamType, false,
-                                     ObjCLifetimeConversion))
+                                     ObjCLifetimeConversion, ConvType))
       return NPV_NullPointer;
 
     // The types didn't match, but we know we got a null pointer; complain,
@@ -5884,10 +5885,11 @@
     Sema &S, NonTypeTemplateParmDecl *Param, QualType ParamType, Expr *ArgIn,
     Expr *Arg, QualType ArgType) {
   bool ObjCLifetimeConversion;
+  Sema::AssignConvertType ConvType = Sema::Compatible;
   if (ParamType->isPointerType() &&
       !ParamType->castAs<PointerType>()->getPointeeType()->isFunctionType() &&
       S.IsQualificationConversion(ArgType, ParamType, false,
-                                  ObjCLifetimeConversion)) {
+                                  ObjCLifetimeConversion, ConvType)) {
     // For pointer-to-object types, qualification conversions are
     // permitted.
   } else {
@@ -6303,10 +6305,10 @@
   case NPV_NotNullPointer:
     break;
   }
-
+  Sema::AssignConvertType ConvType = Sema::Compatible;
   if (S.IsQualificationConversion(ResultArg->getType(),
                                   ParamType.getNonReferenceType(), false,
-                                  ObjCLifetimeConversion)) {
+                                  ObjCLifetimeConversion, ConvType)) {
     ResultArg = S.ImpCastExprToType(ResultArg, ParamType, CK_NoOp,
                                     ResultArg->getValueKind())
                     .get();
Index: clang/lib/Sema/SemaOverload.cpp
===================================================================
--- clang/lib/Sema/SemaOverload.cpp
+++ clang/lib/Sema/SemaOverload.cpp
@@ -80,7 +80,8 @@
                                  bool InOverloadResolution,
                                  StandardConversionSequence &SCS,
                                  bool CStyle,
-                                 bool AllowObjCWritebackConversion);
+                                 bool AllowObjCWritebackConversion,
+                                 Sema::AssignConvertType& ConvType);
 
 static bool IsTransparentUnionStandardConversion(Sema &S, Expr* From,
                                                  QualType &ToType,
@@ -1424,10 +1425,11 @@
                       bool InOverloadResolution,
                       bool CStyle,
                       bool AllowObjCWritebackConversion,
-                      bool AllowObjCConversionOnExplicit) {
+                      bool AllowObjCConversionOnExplicit,
+                      Sema::AssignConvertType& ConvType) {
   ImplicitConversionSequence ICS;
   if (IsStandardConversion(S, From, ToType, InOverloadResolution,
-                           ICS.Standard, CStyle, AllowObjCWritebackConversion)){
+                           ICS.Standard, CStyle, AllowObjCWritebackConversion, ConvType)){
     ICS.setStandard();
     return ICS;
   }
@@ -1479,11 +1481,12 @@
                             bool InOverloadResolution,
                             bool CStyle,
                             bool AllowObjCWritebackConversion) {
+  Sema::AssignConvertType ConvTy;
   return ::TryImplicitConversion(*this, From, ToType,
                                  SuppressUserConversions, AllowExplicit,
                                  InOverloadResolution, CStyle,
                                  AllowObjCWritebackConversion,
-                                 /*AllowObjCConversionOnExplicit=*/false);
+                                 /*AllowObjCConversionOnExplicit=*/false, ConvTy);
 }
 
 /// PerformImplicitConversion - Perform an implicit conversion of the
@@ -1493,15 +1496,18 @@
 /// explicit user-defined conversions are permitted.
 ExprResult
 Sema::PerformImplicitConversion(Expr *From, QualType ToType,
-                                AssignmentAction Action, bool AllowExplicit) {
+                                AssignmentAction Action,
+                                /*Sema::AssignConvertType& ConvTy,*/ bool AllowExplicit) {
   ImplicitConversionSequence ICS;
-  return PerformImplicitConversion(From, ToType, Action, AllowExplicit, ICS);
+  Sema::AssignConvertType ConvTy = Compatible;
+  return PerformImplicitConversion(From, ToType, Action, AllowExplicit, ICS, ConvTy);
 }
 
 ExprResult
 Sema::PerformImplicitConversion(Expr *From, QualType ToType,
                                 AssignmentAction Action, bool AllowExplicit,
-                                ImplicitConversionSequence& ICS) {
+                                ImplicitConversionSequence& ICS,
+                                Sema::AssignConvertType& ConvTy) {
   if (checkPlaceholderForOverload(*this, From))
     return ExprError();
 
@@ -1518,8 +1524,9 @@
                                 /*InOverloadResolution=*/false,
                                 /*CStyle=*/false,
                                 AllowObjCWritebackConversion,
-                                /*AllowObjCConversionOnExplicit=*/false);
-  return PerformImplicitConversion(From, ToType, ICS, Action);
+                                /*AllowObjCConversionOnExplicit=*/false,
+                                ConvTy);
+  return PerformImplicitConversion(From, ToType, ICS, Action, ConvTy);
 }
 
 /// Determine whether the conversion from FromType to ToType is a valid
@@ -1681,7 +1688,8 @@
                                  bool InOverloadResolution,
                                  StandardConversionSequence &SCS,
                                  bool CStyle,
-                                 bool AllowObjCWritebackConversion) {
+                                 bool AllowObjCWritebackConversion,
+                                 Sema::AssignConvertType& ConvType) {
   QualType FromType = From->getType();
 
   // Standard conversions (C++ [conv])
@@ -1949,7 +1957,7 @@
     // 'noreturn' (Clang extension).
     SCS.Third = ICK_Function_Conversion;
   } else if (S.IsQualificationConversion(FromType, ToType, CStyle,
-                                         ObjCLifetimeConversion)) {
+                                         ObjCLifetimeConversion, ConvType)) {
     SCS.Third = ICK_Qualification;
     SCS.QualificationIncludesObjCLifetime = ObjCLifetimeConversion;
     FromType = ToType;
@@ -2033,8 +2041,9 @@
   RecordDecl *UD = UT->getDecl();
   // It's compatible if the expression matches any of the fields.
   for (const auto *it : UD->fields()) {
+    Sema::AssignConvertType ConvType = Sema::Compatible;
     if (IsStandardConversion(S, From, it->getType(), InOverloadResolution, SCS,
-                             CStyle, /*AllowObjCWritebackConversion=*/false)) {
+                             CStyle, /*AllowObjCWritebackConversion=*/false, ConvType)) {
       ToType = it->getType();
       return true;
     }
@@ -3178,7 +3187,8 @@
 static bool isQualificationConversionStep(QualType FromType, QualType ToType,
                                           bool CStyle, bool IsTopLevel,
                                           bool &PreviousToQualsIncludeConst,
-                                          bool &ObjCLifetimeConversion) {
+                                          bool &ObjCLifetimeConversion,
+                                          Sema::AssignConvertType& ConvType) {
   Qualifiers FromQuals = FromType.getQualifiers();
   Qualifiers ToQuals = ToType.getQualifiers();
 
@@ -3218,11 +3228,14 @@
   //    superset in all cases apart from C-style casts where we allow
   //    conversions between overlapping address spaces.
   //  - in non-top levels it is not a valid conversion.
-  if (ToQuals.getAddressSpace() != FromQuals.getAddressSpace() &&
-      (!IsTopLevel ||
-       !(ToQuals.isAddressSpaceSupersetOf(FromQuals) ||
-         (CStyle && FromQuals.isAddressSpaceSupersetOf(ToQuals)))))
+  if (ToQuals.getAddressSpace() != FromQuals.getAddressSpace()) {
+    if (!IsTopLevel)
+      ConvType = Sema::IncompatibleNestedPointerAddressSpaceMismatch;
+    else if ((ToQuals.isAddressSpaceSupersetOf(FromQuals) ||
+             (CStyle && FromQuals.isAddressSpaceSupersetOf(ToQuals))))
+      return true;
     return false;
+  }
 
   //   -- if the cv 1,j and cv 2,j are different, then const is in
   //      every cv for 0 < k < j.
@@ -3246,7 +3259,8 @@
 /// object lifetime.
 bool
 Sema::IsQualificationConversion(QualType FromType, QualType ToType,
-                                bool CStyle, bool &ObjCLifetimeConversion) {
+                                bool CStyle, bool &ObjCLifetimeConversion,
+                                Sema::AssignConvertType& ConvType) {
   FromType = Context.getCanonicalType(FromType);
   ToType = Context.getCanonicalType(ToType);
   ObjCLifetimeConversion = false;
@@ -3264,7 +3278,7 @@
   while (Context.UnwrapSimilarTypes(FromType, ToType)) {
     if (!isQualificationConversionStep(
             FromType, ToType, CStyle, !UnwrappedAnyPointer,
-            PreviousToQualsIncludeConst, ObjCLifetimeConversion))
+            PreviousToQualsIncludeConst, ObjCLifetimeConversion, ConvType))
       return false;
     UnwrappedAnyPointer = true;
   }
@@ -3291,9 +3305,10 @@
     return false;
 
   StandardConversionSequence InnerSCS;
+  Sema::AssignConvertType ConvType = Sema::Compatible;
   if (!IsStandardConversion(S, From, ToAtomic->getValueType(),
                             InOverloadResolution, InnerSCS,
-                            CStyle, /*AllowObjCWritebackConversion=*/false))
+                            CStyle, /*AllowObjCWritebackConversion=*/false, ConvType))
     return false;
 
   SCS.Second = InnerSCS.Second;
@@ -4508,9 +4523,10 @@
     // If we find a qualifier mismatch, the types are not reference-compatible,
     // but are still be reference-related if they're similar.
     bool ObjCLifetimeConversion = false;
+    AssignConvertType ConvType = Compatible;
     if (!isQualificationConversionStep(T2, T1, /*CStyle=*/false, TopLevel,
                                        PreviousToQualsIncludeConst,
-                                       ObjCLifetimeConversion))
+                                       ObjCLifetimeConversion, ConvType))
       return (ConvertedReferent || Context.hasSimilarType(T1, T2))
                  ? Ref_Related
                  : Ref_Incompatible;
@@ -4867,12 +4883,13 @@
   //   the argument expression. Any difference in top-level
   //   cv-qualification is subsumed by the initialization itself
   //   and does not constitute a conversion.
+  Sema::AssignConvertType ConvType = Sema::Compatible;
   ICS = TryImplicitConversion(S, Init, T1, SuppressUserConversions,
                               /*AllowExplicit=*/false,
                               /*InOverloadResolution=*/false,
                               /*CStyle=*/false,
                               /*AllowObjCWritebackConversion=*/false,
-                              /*AllowObjCConversionOnExplicit=*/false);
+                              /*AllowObjCConversionOnExplicit=*/false, ConvType);
 
   // Of course, that's still a reference binding.
   if (ICS.isStandard()) {
@@ -5187,13 +5204,15 @@
                             /*FIXME:*/ From->getBeginLoc(),
                             SuppressUserConversions, AllowExplicit);
 
+  Sema::AssignConvertType ConvType = Sema::Compatible;
+
   return TryImplicitConversion(S, From, ToType,
                                SuppressUserConversions,
                                /*AllowExplicit=*/false,
                                InOverloadResolution,
                                /*CStyle=*/false,
                                AllowObjCWritebackConversion,
-                               /*AllowObjCConversionOnExplicit=*/false);
+                               /*AllowObjCConversionOnExplicit=*/false, ConvType);
 }
 
 static bool TryCopyInitialization(const CanQualType FromQTy,
@@ -5435,13 +5454,14 @@
 /// expression From to bool (C++0x [conv]p3).
 static ImplicitConversionSequence
 TryContextuallyConvertToBool(Sema &S, Expr *From) {
+  Sema::AssignConvertType ConvType = Sema::Compatible;
   return TryImplicitConversion(S, From, S.Context.BoolTy,
                                /*SuppressUserConversions=*/false,
                                /*AllowExplicit=*/true,
                                /*InOverloadResolution=*/false,
                                /*CStyle=*/false,
                                /*AllowObjCWritebackConversion=*/false,
-                               /*AllowObjCConversionOnExplicit=*/false);
+                               /*AllowObjCConversionOnExplicit=*/false, ConvType);
 }
 
 /// PerformContextuallyConvertToBool - Perform a contextual conversion
@@ -5451,8 +5471,10 @@
     return ExprError();
 
   ImplicitConversionSequence ICS = TryContextuallyConvertToBool(*this, From);
-  if (!ICS.isBad())
-    return PerformImplicitConversion(From, Context.BoolTy, ICS, AA_Converting);
+  if (!ICS.isBad()) {
+    Sema::AssignConvertType ConvType = Sema::Compatible;
+    return PerformImplicitConversion(From, Context.BoolTy, ICS, AA_Converting, ConvType);
+  }
 
   if (!DiagnoseMultipleUserDefinedConversion(From, Context.BoolTy))
     return Diag(From->getBeginLoc(), diag::err_typecheck_bool_condition)
@@ -5590,9 +5612,9 @@
                   diag::err_typecheck_converted_constant_expression_indirect)
            << From->getType() << From->getSourceRange() << T;
   }
-
+  Sema::AssignConvertType ConvType = Sema::Compatible;
   ExprResult Result =
-      S.PerformImplicitConversion(From, T, ICS, Sema::AA_Converting);
+      S.PerformImplicitConversion(From, T, ICS, Sema::AA_Converting, ConvType);
   if (Result.isInvalid())
     return Result;
 
@@ -5705,6 +5727,7 @@
 TryContextuallyConvertToObjCPointer(Sema &S, Expr *From) {
   // Do an implicit conversion to 'id'.
   QualType Ty = S.Context.getObjCIdType();
+  Sema::AssignConvertType ConvType = Sema::Compatible;
   ImplicitConversionSequence ICS
     = TryImplicitConversion(S, From, Ty,
                             // FIXME: Are these flags correct?
@@ -5713,7 +5736,7 @@
                             /*InOverloadResolution=*/false,
                             /*CStyle=*/false,
                             /*AllowObjCWritebackConversion=*/false,
-                            /*AllowObjCConversionOnExplicit=*/true);
+                            /*AllowObjCConversionOnExplicit=*/true, ConvType);
 
   // Strip off any final conversions to 'id'.
   switch (ICS.getKind()) {
@@ -5744,8 +5767,10 @@
   QualType Ty = Context.getObjCIdType();
   ImplicitConversionSequence ICS =
     TryContextuallyConvertToObjCPointer(*this, From);
-  if (!ICS.isBad())
-    return PerformImplicitConversion(From, Ty, ICS, AA_Converting);
+  if (!ICS.isBad()) {
+    Sema::AssignConvertType ConvType = Sema::Compatible;
+    return PerformImplicitConversion(From, Ty, ICS, AA_Converting, ConvType);
+  }
   return ExprResult();
 }
 
@@ -7108,8 +7133,9 @@
 
   // Allow qualification conversions.
   bool ObjCLifetimeConversion;
+  Sema::AssignConvertType Conv = Sema::Compatible;
   if (S.IsQualificationConversion(ConvType, ToNonRefType, /*CStyle*/false,
-                                  ObjCLifetimeConversion))
+                                  ObjCLifetimeConversion, Conv))
     return true;
 
   // If we're not allowed to consider Objective-C pointer conversions,
@@ -13000,9 +13026,10 @@
       // We matched a built-in operator. Convert the arguments, then
       // break out so that we will build the appropriate built-in
       // operator node.
+      Sema::AssignConvertType ConvType = Sema::Compatible;   
       ExprResult InputRes = PerformImplicitConversion(
           Input, Best->BuiltinParamTypes[0], Best->Conversions[0], AA_Passing,
-          CCK_ForBuiltinOverloadedOp);
+          ConvType, CCK_ForBuiltinOverloadedOp);
       if (InputRes.isInvalid())
         return ExprError();
       Input = InputRes.get();
@@ -13391,16 +13418,17 @@
         // We matched a built-in operator. Convert the arguments, then
         // break out so that we will build the appropriate built-in
         // operator node.
+        Sema::AssignConvertType ConvType = Sema::Compatible;
         ExprResult ArgsRes0 = PerformImplicitConversion(
             Args[0], Best->BuiltinParamTypes[0], Best->Conversions[0],
-            AA_Passing, CCK_ForBuiltinOverloadedOp);
+            AA_Passing, ConvType, CCK_ForBuiltinOverloadedOp);
         if (ArgsRes0.isInvalid())
           return ExprError();
         Args[0] = ArgsRes0.get();
 
         ExprResult ArgsRes1 = PerformImplicitConversion(
             Args[1], Best->BuiltinParamTypes[1], Best->Conversions[1],
-            AA_Passing, CCK_ForBuiltinOverloadedOp);
+            AA_Passing, ConvType, CCK_ForBuiltinOverloadedOp);
         if (ArgsRes1.isInvalid())
           return ExprError();
         Args[1] = ArgsRes1.get();
@@ -13713,16 +13741,17 @@
         // We matched a built-in operator. Convert the arguments, then
         // break out so that we will build the appropriate built-in
         // operator node.
+        Sema::AssignConvertType ConvType = Sema::Compatible;
         ExprResult ArgsRes0 = PerformImplicitConversion(
             Args[0], Best->BuiltinParamTypes[0], Best->Conversions[0],
-            AA_Passing, CCK_ForBuiltinOverloadedOp);
+            AA_Passing, ConvType, CCK_ForBuiltinOverloadedOp);
         if (ArgsRes0.isInvalid())
           return ExprError();
         Args[0] = ArgsRes0.get();
 
         ExprResult ArgsRes1 = PerformImplicitConversion(
             Args[1], Best->BuiltinParamTypes[1], Best->Conversions[1],
-            AA_Passing, CCK_ForBuiltinOverloadedOp);
+            AA_Passing, ConvType, CCK_ForBuiltinOverloadedOp);
         if (ArgsRes1.isInvalid())
           return ExprError();
         Args[1] = ArgsRes1.get();
Index: clang/lib/Sema/SemaInit.cpp
===================================================================
--- clang/lib/Sema/SemaInit.cpp
+++ clang/lib/Sema/SemaInit.cpp
@@ -8171,9 +8171,10 @@
         : Kind.isFunctionalCast()? Sema::CCK_FunctionalCast
         : Kind.isExplicitCast()? Sema::CCK_OtherCast
         : Sema::CCK_ImplicitConversion;
+      Sema::AssignConvertType ConvType = Sema::Compatible;
       ExprResult CurInitExprRes =
         S.PerformImplicitConversion(CurInit.get(), Step->Type, *Step->ICS,
-                                    getAssignmentAction(Entity), CCK);
+                                    getAssignmentAction(Entity), ConvType, CCK);
       if (CurInitExprRes.isInvalid())
         return ExprError();
 
Index: clang/lib/Sema/SemaExprCXX.cpp
===================================================================
--- clang/lib/Sema/SemaExprCXX.cpp
+++ clang/lib/Sema/SemaExprCXX.cpp
@@ -3790,7 +3790,7 @@
 ExprResult
 Sema::PerformImplicitConversion(Expr *From, QualType ToType,
                                 const ImplicitConversionSequence &ICS,
-                                AssignmentAction Action,
+                                AssignmentAction Action, Sema::AssignConvertType& ConvType,
                                 CheckedConversionKind CCK) {
   // C++ [over.match.oper]p7: [...] operands of class type are converted [...]
   if (CCK == CCK_ForBuiltinOverloadedOp && !From->getType()->isRecordType())
@@ -3872,9 +3872,9 @@
 
   case ImplicitConversionSequence::BadConversion:
     bool Diagnosed =
-        DiagnoseAssignmentResult(Incompatible, From->getExprLoc(), ToType,
+        DiagnoseAssignmentResult(ConvType==Compatible ? Incompatible : ConvType,
+                                 From->getExprLoc(), ToType,
                                  From->getType(), From, Action);
-    assert(Diagnosed && "failed to diagnose bad conversion"); (void)Diagnosed;
     return ExprError();
   }
 
@@ -5686,16 +5686,17 @@
   switch (CandidateSet.BestViableFunction(Self, QuestionLoc, Best)) {
     case OR_Success: {
       // We found a match. Perform the conversions on the arguments and move on.
+      Sema::AssignConvertType ConvType = Sema::Compatible;
       ExprResult LHSRes = Self.PerformImplicitConversion(
           LHS.get(), Best->BuiltinParamTypes[0], Best->Conversions[0],
-          Sema::AA_Converting);
+          Sema::AA_Converting, ConvType);
       if (LHSRes.isInvalid())
         break;
       LHS = LHSRes;
 
       ExprResult RHSRes = Self.PerformImplicitConversion(
           RHS.get(), Best->BuiltinParamTypes[1], Best->Conversions[1],
-          Sema::AA_Converting);
+          Sema::AA_Converting, ConvType);
       if (RHSRes.isInvalid())
         break;
       RHS = RHSRes;
Index: clang/lib/Sema/SemaExpr.cpp
===================================================================
--- clang/lib/Sema/SemaExpr.cpp
+++ clang/lib/Sema/SemaExpr.cpp
@@ -8684,9 +8684,10 @@
       // expression is implicitly converted (C++ 4) to the
       // cv-unqualified type of the left operand.
       QualType RHSType = RHS.get()->getType();
+      Sema::AssignConvertType ConvType = Compatible;
       if (Diagnose) {
         RHS = PerformImplicitConversion(RHS.get(), LHSType.getUnqualifiedType(),
-                                        AA_Assigning);
+                                        AA_Assigning, ConvType);
       } else {
         ImplicitConversionSequence ICS =
             TryImplicitConversion(RHS.get(), LHSType.getUnqualifiedType(),
@@ -8698,15 +8699,19 @@
         if (ICS.isFailure())
           return Incompatible;
         RHS = PerformImplicitConversion(RHS.get(), LHSType.getUnqualifiedType(),
-                                        ICS, AA_Assigning);
+                                        ICS, AA_Assigning, ConvType);
       }
-      if (RHS.isInvalid())
-        return Incompatible;
-      Sema::AssignConvertType result = Compatible;
-      if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() &&
-          !CheckObjCARCUnavailableWeakConversion(LHSType, RHSType))
-        result = IncompatibleObjCWeakRef;
-      return result;
+      // FIXME: We won't need this check if PerformImplicitConversion sets
+      // AssignConvertType correctly.
+      if (ConvType == Compatible && RHS.isInvalid())
+        ConvType = Incompatible;
+
+      if (ConvType == Compatible) 
+        if (getLangOpts().allowsNonTrivialObjCLifetimeQualifiers() &&
+            !CheckObjCARCUnavailableWeakConversion(LHSType, RHSType))
+          ConvType = IncompatibleObjCWeakRef;
+
+      return ConvType;
     }
 
     // FIXME: Currently, we fall through and treat C++ classes like C
Index: clang/lib/Sema/SemaExceptionSpec.cpp
===================================================================
--- clang/lib/Sema/SemaExceptionSpec.cpp
+++ clang/lib/Sema/SemaExceptionSpec.cpp
@@ -696,8 +696,9 @@
     QualType Result;
     // FIXME: Should we treat the exception as catchable if a lifetime
     // conversion is required?
+    Sema::AssignConvertType ConvType = Sema::Compatible;
     if (IsQualificationConversion(ExceptionType, HandlerType, false,
-                                  LifetimeConv) ||
+                                  LifetimeConv, ConvType) ||
         IsFunctionConversion(ExceptionType, HandlerType, Result))
       return true;
 
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -2868,6 +2868,83 @@
     AA_Casting,
     AA_Passing_CFAudited
   };
+  /// AssignConvertType - All of the 'assignment' semantic checks return this
+  /// enum to indicate whether the assignment was allowed.  These checks are
+  /// done for simple assignments, as well as initialization, return from
+  /// function, argument passing, etc.  The query is phrased in terms of a
+  /// source and destination type.
+  enum AssignConvertType {
+    /// Compatible - the types are compatible according to the standard.
+    Compatible,
+
+    /// PointerToInt - The assignment converts a pointer to an int, which we
+    /// accept as an extension.
+    PointerToInt,
+
+    /// IntToPointer - The assignment converts an int to a pointer, which we
+    /// accept as an extension.
+    IntToPointer,
+
+    /// FunctionVoidPointer - The assignment is between a function pointer and
+    /// void*, which the standard doesn't allow, but we accept as an extension.
+    FunctionVoidPointer,
+
+    /// IncompatiblePointer - The assignment is between two pointers types that
+    /// are not compatible, but we accept them as an extension.
+    IncompatiblePointer,
+
+    /// IncompatiblePointerSign - The assignment is between two pointers types
+    /// which point to integers which have a different sign, but are otherwise
+    /// identical. This is a subset of the above, but broken out because it's by
+    /// far the most common case of incompatible pointers.
+    IncompatiblePointerSign,
+
+    /// CompatiblePointerDiscardsQualifiers - The assignment discards
+    /// c/v/r qualifiers, which we accept as an extension.
+    CompatiblePointerDiscardsQualifiers,
+
+    /// IncompatiblePointerDiscardsQualifiers - The assignment
+    /// discards qualifiers that we don't permit to be discarded,
+    /// like address spaces.
+    IncompatiblePointerDiscardsQualifiers,
+
+    /// IncompatibleNestedPointerAddressSpaceMismatch - The assignment
+    /// changes address spaces in nested pointer types which is not allowed.
+    /// For instance, converting __private int ** to __generic int ** is
+    /// illegal even though __private could be converted to __generic.
+    IncompatibleNestedPointerAddressSpaceMismatch,
+
+    /// IncompatibleNestedPointerQualifiers - The assignment is between two
+    /// nested pointer types, and the qualifiers other than the first two
+    /// levels differ e.g. char ** -> const char **, but we accept them as an
+    /// extension.
+    IncompatibleNestedPointerQualifiers,
+
+    /// IncompatibleVectors - The assignment is between two vector types that
+    /// have the same size, which we accept as an extension.
+    IncompatibleVectors,
+
+    /// IntToBlockPointer - The assignment converts an int to a block
+    /// pointer. We disallow this.
+    IntToBlockPointer,
+
+    /// IncompatibleBlockPointer - The assignment is between two block
+    /// pointers types that are not compatible.
+    IncompatibleBlockPointer,
+
+    /// IncompatibleObjCQualifiedId - The assignment is between a qualified
+    /// id type and something else (that is incompatible with it). For example,
+    /// "id <XXX>" = "Foo *", where "Foo *" doesn't implement the XXX protocol.
+    IncompatibleObjCQualifiedId,
+
+    /// IncompatibleObjCWeakRef - Assigning a weak-unavailable object to an
+    /// object with __weak qualifier.
+    IncompatibleObjCWeakRef,
+
+    /// Incompatible - We reject this conversion outright, it is invalid to
+    /// represent it in the AST.
+    Incompatible
+  };
 
   /// C++ Overloading.
   enum OverloadKind {
@@ -2933,7 +3010,8 @@
                                     CXXCastPath &BasePath,
                                     bool IgnoreBaseAccess);
   bool IsQualificationConversion(QualType FromType, QualType ToType,
-                                 bool CStyle, bool &ObjCLifetimeConversion);
+                                 bool CStyle, bool &ObjCLifetimeConversion,
+                                 AssignConvertType &ConvType);
   bool IsFunctionConversion(QualType FromType, QualType ToType,
                             QualType &ResultTy);
   bool DiagnoseMultipleUserDefinedConversion(Expr *From, QualType ToType);
@@ -10466,83 +10544,7 @@
   QualType UsualArithmeticConversions(ExprResult &LHS, ExprResult &RHS,
                                       SourceLocation Loc, ArithConvKind ACK);
 
-  /// AssignConvertType - All of the 'assignment' semantic checks return this
-  /// enum to indicate whether the assignment was allowed.  These checks are
-  /// done for simple assignments, as well as initialization, return from
-  /// function, argument passing, etc.  The query is phrased in terms of a
-  /// source and destination type.
-  enum AssignConvertType {
-    /// Compatible - the types are compatible according to the standard.
-    Compatible,
-
-    /// PointerToInt - The assignment converts a pointer to an int, which we
-    /// accept as an extension.
-    PointerToInt,
-
-    /// IntToPointer - The assignment converts an int to a pointer, which we
-    /// accept as an extension.
-    IntToPointer,
 
-    /// FunctionVoidPointer - The assignment is between a function pointer and
-    /// void*, which the standard doesn't allow, but we accept as an extension.
-    FunctionVoidPointer,
-
-    /// IncompatiblePointer - The assignment is between two pointers types that
-    /// are not compatible, but we accept them as an extension.
-    IncompatiblePointer,
-
-    /// IncompatiblePointerSign - The assignment is between two pointers types
-    /// which point to integers which have a different sign, but are otherwise
-    /// identical. This is a subset of the above, but broken out because it's by
-    /// far the most common case of incompatible pointers.
-    IncompatiblePointerSign,
-
-    /// CompatiblePointerDiscardsQualifiers - The assignment discards
-    /// c/v/r qualifiers, which we accept as an extension.
-    CompatiblePointerDiscardsQualifiers,
-
-    /// IncompatiblePointerDiscardsQualifiers - The assignment
-    /// discards qualifiers that we don't permit to be discarded,
-    /// like address spaces.
-    IncompatiblePointerDiscardsQualifiers,
-
-    /// IncompatibleNestedPointerAddressSpaceMismatch - The assignment
-    /// changes address spaces in nested pointer types which is not allowed.
-    /// For instance, converting __private int ** to __generic int ** is
-    /// illegal even though __private could be converted to __generic.
-    IncompatibleNestedPointerAddressSpaceMismatch,
-
-    /// IncompatibleNestedPointerQualifiers - The assignment is between two
-    /// nested pointer types, and the qualifiers other than the first two
-    /// levels differ e.g. char ** -> const char **, but we accept them as an
-    /// extension.
-    IncompatibleNestedPointerQualifiers,
-
-    /// IncompatibleVectors - The assignment is between two vector types that
-    /// have the same size, which we accept as an extension.
-    IncompatibleVectors,
-
-    /// IntToBlockPointer - The assignment converts an int to a block
-    /// pointer. We disallow this.
-    IntToBlockPointer,
-
-    /// IncompatibleBlockPointer - The assignment is between two block
-    /// pointers types that are not compatible.
-    IncompatibleBlockPointer,
-
-    /// IncompatibleObjCQualifiedId - The assignment is between a qualified
-    /// id type and something else (that is incompatible with it). For example,
-    /// "id <XXX>" = "Foo *", where "Foo *" doesn't implement the XXX protocol.
-    IncompatibleObjCQualifiedId,
-
-    /// IncompatibleObjCWeakRef - Assigning a weak-unavailable object to an
-    /// object with __weak qualifier.
-    IncompatibleObjCWeakRef,
-
-    /// Incompatible - We reject this conversion outright, it is invalid to
-    /// represent it in the AST.
-    Incompatible
-  };
 
   /// DiagnoseAssignmentResult - Emit a diagnostic, if required, for the
   /// assignment conversion type specified by ConvTy.  This returns true if the
@@ -10555,7 +10557,7 @@
 
   /// IsValueInFlagEnum - Determine if a value is allowed as part of a flag
   /// enum. If AllowMask is true, then we also allow the complement of a valid
-  /// value, to be used as a mask.
+  /// value, to be used as a mask.//
   bool IsValueInFlagEnum(const EnumDecl *ED, const llvm::APInt &Val,
                          bool AllowMask) const;
 
@@ -10608,14 +10610,17 @@
 
   ExprResult PerformImplicitConversion(Expr *From, QualType ToType,
                                        AssignmentAction Action,
+                                       /*clang::Sema::AssignConvertType& ConvType,*/
                                        bool AllowExplicit = false);
   ExprResult PerformImplicitConversion(Expr *From, QualType ToType,
                                        AssignmentAction Action,
                                        bool AllowExplicit,
-                                       ImplicitConversionSequence& ICS);
+                                       ImplicitConversionSequence& ICS,
+                                       Sema::AssignConvertType& ConvType);
   ExprResult PerformImplicitConversion(Expr *From, QualType ToType,
                                        const ImplicitConversionSequence& ICS,
-                                       AssignmentAction Action,
+                                       AssignmentAction Action, 
+                                       Sema::AssignConvertType& ConvType,
                                        CheckedConversionKind CCK
                                           = CCK_ImplicitConversion);
   ExprResult PerformImplicitConversion(Expr *From, QualType ToType,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to